Files
be_happy_public/lib/presentation/screens/phone_screen.dart
2026-05-12 12:02:40 +03:00

249 lines
9.7 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:be_happy/presentation/event/spalsh_event.dart';
import 'package:be_happy/presentation/state/splash_state.dart';
import 'package:be_happy/presentation/viewmodel/splash_bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import '../../../core/app_colors.dart';
import '../components/app_checkbox.dart';
import '../components/gradient_button.dart';
import '../event/auth_event.dart';
import '../state/auth_state.dart';
import '../viewmodel/auth_bloc.dart';
import 'phone_login_screen.dart';
class PhoneScreen extends StatefulWidget {
const PhoneScreen({Key? key}) : super(key: key);
@override
State<PhoneScreen> createState() => _PhoneScreenState();
}
class _PhoneScreenState extends State<PhoneScreen> {
final TextEditingController _phoneController = TextEditingController();
@override
void dispose() {
_phoneController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocConsumer<PhoneAuthBloc, PhoneAuthState>(
listener: (context, state) {
if (state.isSuccess) {
context.go("/verify?phone=+375${state.phone}");
context.read<SplashBloc>().add(AuthStarted());
} else if (state.error != null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(state.error!)),
);
}
},
builder: (context, state) {
final isAdult = state.isAdult ?? false;
final privacyAccepted = state.privacyAccepted ?? false;
return Scaffold(
backgroundColor: Colors.transparent,
resizeToAvoidBottomInset: false,
body: Container(
decoration: const BoxDecoration(
gradient: AppColors.phoneScreenBg,
),
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(height: 30),
Image.asset(
'assets/wave.png',
width: double.infinity,
fit: BoxFit.cover,
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Column(
children: [
const SizedBox(height: 20),
const Text(
'Введите номер телефона',
style: TextStyle(
color: AppColors.whiteText,
fontSize: 20,
),
),
const SizedBox(height: 40),
TextField(
controller: _phoneController,
keyboardType: TextInputType.phone,
style: const TextStyle(color: AppColors.whiteText),
decoration: InputDecoration(
filled: true,
fillColor: AppColors.disabledButtonColor,
prefixText: '+375 ',
prefixStyle: const TextStyle(
color: AppColors.whiteText,
fontSize: 16,
),
hintText: 'Номер телефона',
hintStyle: const TextStyle(color: AppColors.hint),
suffixIcon: _phoneController.text.isNotEmpty
? IconButton(
icon: const Icon(Icons.clear,
color: AppColors.whiteText),
onPressed: () {
_phoneController.clear();
context.read<PhoneAuthBloc>().add(PhoneChanged(""));
},
)
: null,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide.none,
),
),
onChanged: (value) {
context.read<PhoneAuthBloc>().add(PhoneChanged(value));
},
),
const SizedBox(height: 24),
Row(
children: [
AppCheckbox(
value: isAdult,
onChanged: (bool? value) {
if (value != null) {
context.read<PhoneAuthBloc>().add(IsAdultChanged(value));
}
},
isError: state.error != null && !isAdult,
),
const SizedBox(width: 12),
Flexible(
child: Text.rich(
TextSpan(
text: 'Подтверждаю, что мне исполнилось 18 лет и я принял ',
style: const TextStyle(
color: AppColors.white70,
fontSize: 12,
),
children: [
WidgetSpan(
child: ClickableText(
text: 'Условия использования сервиса',
onTap: () => context.push('/license-agreement'),
),
),
],
),
),
),
],
),
const SizedBox(height: 14),
Row(
children: [
AppCheckbox(
value: privacyAccepted,
onChanged: (bool? value) {
if (value != null) {
context.read<PhoneAuthBloc>().add(PrivacyAcceptedChanged(value));
}
},
isError: state.error != null && !privacyAccepted,
),
const SizedBox(width: 12),
Expanded(
child: Text.rich(
TextSpan(
text: 'Подтверждаю, что я ознакомился с ',
style: const TextStyle(
color: AppColors.white70,
fontSize: 12,
),
children: [
WidgetSpan(
child: ClickableText(
text: 'Политикой обработки персональных данных',
onTap: () => context.push('/privacy-policy'),
),
),
],
),
),
),
],
),
const SizedBox(height: 47),
GradientButton(
text: "Получить код",
enabled: state.phone.isNotEmpty &&
isAdult &&
privacyAccepted &&
!state.isSubmitting,
onTap: state.isSubmitting
? null
: () {
context.read<PhoneAuthBloc>().add(SubmitPhonePressed());
},
showArrows: true,
height: 50,
width: 340,
fontSize: 14,
),
],
),
),
),
],
),
),
),
);
},
);
}
}
// 🔹 Кликабельный текст для политики
class ClickableText extends StatelessWidget {
final String text;
final VoidCallback onTap;
const ClickableText({
super.key,
required this.text,
required this.onTap,
});
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
child: Text(
text,
style: const TextStyle(
color: Colors.blueAccent,
decorationColor: Colors.blueAccent,
decoration: TextDecoration.underline,
fontSize: 12
),
),
);
}
}