181 lines
6.9 KiB
Dart
181 lines
6.9 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import '../../../core/l10n/app_localizations.dart';
|
|
import '../../../core/design/tokens.dart';
|
|
import '../cubit/auth_cubit.dart';
|
|
import '../cubit/auth_state.dart';
|
|
import '../../../core/ui/tripz_scaffold.dart';
|
|
import '../../../core/ui/tripz_button.dart';
|
|
import '../../../core/ui/tripz_text_field.dart';
|
|
|
|
/// شاشة إدخال الاسم (أول دخول فقط) — تطابق stitch/name_entry.html:
|
|
/// شعار صغير بالمنتصف أعلى الشاشة + عنوان وسطر فرعي + بطاقة بيضاء
|
|
/// مرفوعة فيها حقل الاسم بأيقونة، وزر متابعة أسفل الشاشة.
|
|
///
|
|
/// ملاحظة: تصميم Stitch يعرض 3 حقول (الاسم الأول/الأخير/البريد)، لكن
|
|
/// AuthCubit.updateName ينادي PATCH /users/me بحقل name واحد فقط
|
|
/// (docs/29 §3.5 ينص صراحة على «حقل واحد»). الشاشة هنا تستعمل حقلاً
|
|
/// واحداً للاسم الكامل بنفس لغة Stitch البصرية (بطاقة مرفوعة + أيقونة
|
|
/// + label عائم) دون تغيير عقد الـCubit.
|
|
class NameScreen extends StatefulWidget {
|
|
const NameScreen({super.key});
|
|
@override
|
|
State<NameScreen> createState() => _NameScreenState();
|
|
}
|
|
|
|
class _NameScreenState extends State<NameScreen> {
|
|
final _firstNameController = TextEditingController();
|
|
final _lastNameController = TextEditingController();
|
|
bool _valid = false;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_firstNameController.addListener(_validate);
|
|
_lastNameController.addListener(_validate);
|
|
}
|
|
|
|
void _validate() {
|
|
final isValid = _firstNameController.text.trim().isNotEmpty &&
|
|
_lastNameController.text.trim().isNotEmpty;
|
|
if (_valid != isValid) {
|
|
setState(() => _valid = isValid);
|
|
}
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_firstNameController.dispose();
|
|
_lastNameController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
void _submit() {
|
|
if (!_valid) return;
|
|
final fullName =
|
|
'${_firstNameController.text.trim()} ${_lastNameController.text.trim()}';
|
|
context.read<AuthCubit>().updateName(fullName);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final l10n = AppLocalizations.of(context)!;
|
|
final theme = Theme.of(context);
|
|
final cs = theme.colorScheme;
|
|
|
|
return BlocConsumer<AuthCubit, AuthState>(
|
|
listener: (context, state) {
|
|
if (state.status == AuthStatus.error && state.error != null) {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(content: Text(state.error!)),
|
|
);
|
|
}
|
|
},
|
|
builder: (context, state) {
|
|
final isLoading = state.status == AuthStatus.authenticating;
|
|
return TripzScaffold(
|
|
backgroundColor: cs.surfaceContainerLow,
|
|
padding: false,
|
|
bottomAction: TripzButton(
|
|
onPressed: (_valid && !isLoading) ? _submit : null,
|
|
label: l10n.nameButton,
|
|
loading: isLoading,
|
|
),
|
|
child: Column(
|
|
children: [
|
|
// ── رأس الشاشة: زر عودة (يبدأ الجلسة من جديد) + شعار مصغّر ──
|
|
SizedBox(
|
|
height: T.s48,
|
|
child: Row(
|
|
children: [
|
|
IconButton(
|
|
icon: const BackButtonIcon(),
|
|
color: cs.onSurface,
|
|
tooltip: l10n.back,
|
|
onPressed: () => context.read<AuthCubit>().logout(),
|
|
),
|
|
Expanded(
|
|
child: Center(
|
|
child: Image.asset(
|
|
'assets/images/name_hero.png',
|
|
height: T.iconLg,
|
|
fit: BoxFit.contain,
|
|
errorBuilder: (_, __, ___) => Icon(
|
|
Icons.directions_car_filled_rounded,
|
|
size: T.iconLg,
|
|
color: cs.primary,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(width: T.s48),
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(height: T.s24),
|
|
|
|
Expanded(
|
|
child: SingleChildScrollView(
|
|
padding: const EdgeInsets.symmetric(horizontal: T.pagePadding),
|
|
child: Column(
|
|
children: [
|
|
// العنوان والسطر الفرعي
|
|
Text(
|
|
l10n.nameTitle,
|
|
style: theme.textTheme.headlineSmall?.copyWith(
|
|
fontWeight: FontWeight.w600,
|
|
color: cs.onSurface,
|
|
),
|
|
textAlign: TextAlign.center,
|
|
),
|
|
const SizedBox(height: T.s8),
|
|
Text(
|
|
l10n.nameSubtitle,
|
|
style: theme.textTheme.bodyLarge?.copyWith(
|
|
color: cs.onSurfaceVariant,
|
|
),
|
|
textAlign: TextAlign.center,
|
|
),
|
|
const SizedBox(height: T.s24),
|
|
|
|
// بطاقة بيضاء مرفوعة تحوي حقول الاسم الأول واسم العائلة
|
|
Container(
|
|
width: double.infinity,
|
|
padding: const EdgeInsets.all(T.s24),
|
|
decoration: BoxDecoration(
|
|
color: cs.surfaceContainerLowest,
|
|
borderRadius: BorderRadius.circular(T.r16),
|
|
boxShadow: const [T.shadowSm],
|
|
),
|
|
child: Column(
|
|
children: [
|
|
TripzTextField(
|
|
controller: _firstNameController,
|
|
label: l10n.firstNameHint,
|
|
autofocus: true,
|
|
prefix: Icon(Icons.person_outline_rounded, color: cs.outline),
|
|
textInputAction: TextInputAction.next,
|
|
),
|
|
const SizedBox(height: T.s16),
|
|
TripzTextField(
|
|
controller: _lastNameController,
|
|
label: l10n.lastNameHint,
|
|
prefix: Icon(Icons.badge_outlined, color: cs.outline),
|
|
onSubmitted: (_) => _submit(),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
}
|