Files
intaleq_driver/lib/views/auth/captin/login_captin.dart
2025-09-01 19:04:50 +03:00

462 lines
17 KiB
Dart
Executable File

import 'dart:io';
import 'package:sefer_driver/views/auth/captin/contact_us_page.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_font_icons/flutter_font_icons.dart';
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
import 'package:get/get.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../../constant/box_name.dart';
import '../../../constant/colors.dart';
import '../../../constant/info.dart';
import '../../../constant/links.dart';
import '../../../constant/style.dart';
import '../../../controller/auth/apple_sigin.dart';
import '../../../controller/auth/captin/login_captin_controller.dart';
import '../../../controller/auth/google_sign.dart';
import '../../../controller/functions/encrypt_decrypt.dart';
import '../../../controller/functions/overlay_permisssion.dart';
import '../../../main.dart';
import '../../../print.dart';
import '../../widgets/elevated_btn.dart';
import '../../widgets/mycircular.dart';
import '../country_widget.dart';
import 'otp_page.dart';
class LoginCaptin extends StatelessWidget {
final AuthController authController = Get.put(AuthController());
final LoginDriverController controller = Get.put(LoginDriverController());
LoginCaptin({super.key});
@override
Widget build(BuildContext context) {
return GetBuilder<LoginDriverController>(
builder: (controller) {
return Scaffold(
backgroundColor: AppColor.secondaryColor,
body: SafeArea(
child: Center(
child: _buildBodyContent(context, controller),
),
),
);
},
);
}
/// Determines which UI to show based on the driver's progress (agreement, permissions, login).
Widget _buildBodyContent(
BuildContext context, LoginDriverController controller) {
if (box.read(BoxName.agreeTerms) != 'agreed') {
return _buildAgreementPage(context, controller);
}
// if (box.read(BoxName.countryCode) == null) {
// return CountryPicker(); // Assumed to be a full-screen widget
// }
if (box.read(BoxName.locationPermission) != 'true') {
return _buildLocationPermissionPage(context, controller);
}
// Once all permissions are granted, show the main login UI
return PhoneNumberScreen();
}
/// Redesigned UI for the main login screen.
Widget _buildLoginUI(BuildContext context, LoginDriverController controller) {
return SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 32.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Image.asset('assets/images/logo.gif', height: 120, width: 120),
const SizedBox(height: 20),
Text(
'Driver Portal'.tr,
textAlign: TextAlign.center,
style: AppStyle.headTitle2.copyWith(fontSize: 28),
),
const SizedBox(height: 8),
Text(
'Sign in to start your journey'.tr,
textAlign: TextAlign.center,
style: AppStyle.subtitle,
),
const SizedBox(height: 40),
// Conditional UI based on the controller state
if (controller.isGoogleDashOpen)
_buildManualLoginForm(context, controller, isRegistration: true)
else if (Platform.isIOS && controller.isTest == 0)
_buildManualLoginForm(context, controller, isRegistration: false)
else
_buildSocialLoginOptions(context, controller),
const SizedBox(height: 32),
Center(
child: GestureDetector(
onTap: () => Get.to(() => ContactUsPage()),
child: Text(
'Need help? Contact Us'.tr,
style: AppStyle.subtitle.copyWith(
color: AppColor.blueColor,
decoration: TextDecoration.underline,
),
),
),
),
],
),
);
}
/// Builds the social login buttons (Google, Apple, and manual option).
Widget _buildSocialLoginOptions(
BuildContext context, LoginDriverController controller) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'Sign in with a provider for easy access'.tr,
textAlign: TextAlign.center,
style: AppStyle.title,
),
const SizedBox(height: 24),
_buildSocialButton(
text: 'Sign In with Google'.tr,
icon: FontAwesome.google,
backgroundColor: AppColor.redColor,
onPressed: () async {
GoogleSignInHelper().signInFromLogin();
},
),
if (Platform.isIOS) ...[
const SizedBox(height: 16),
_buildSocialButton(
text: 'Sign in with Apple'.tr,
icon: Icons.apple,
backgroundColor: Colors.black,
onPressed: () async {
User? user = await authController.signInWithApple();
if (user != null) {
box.write(BoxName.emailDriver, user.email.toString());
box.write(BoxName.driverID, user.uid);
controller.loginWithGoogleCredential(
user.uid,
user.email.toString(),
);
}
},
),
],
const SizedBox(height: 24),
Row(
children: [
const Expanded(child: Divider()),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Text('Or'.tr, style: AppStyle.subtitle),
),
const Expanded(child: Divider()),
],
),
const SizedBox(height: 24),
MyElevatedButton(
title: 'Create Account with Email'.tr,
onPressed: () => controller.changeGoogleDashOpen(),
kolor: AppColor.blueColor, // Using 'kolor' as in your widget
),
],
);
}
/// Builds the form for manual email/password login or registration.
Widget _buildManualLoginForm(
BuildContext context, LoginDriverController controller,
{required bool isRegistration}) {
return Card(
elevation: 8,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Form(
key: controller.formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
isRegistration ? 'Create Driver Account'.tr : 'Driver Login'.tr,
textAlign: TextAlign.center,
style: AppStyle.headTitle2,
),
const SizedBox(height: 24),
_buildTextFormField(
controller: controller.emailController,
labelText: 'Email'.tr,
hintText: 'Enter your email'.tr,
prefixIcon: Icons.email_outlined,
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value == null || !GetUtils.isEmail(value)) {
return 'Please enter a valid email'.tr;
}
return null;
},
),
const SizedBox(height: 20),
GetBuilder<LoginDriverController>(
id: 'passwordVisibility', // ID to only rebuild this widget
builder: (_) => _buildTextFormField(
controller: controller.passwordController,
labelText: 'Password'.tr,
hintText: 'Enter your password'.tr,
prefixIcon: Icons.lock_outline,
obscureText: controller.isPasswordHidden,
suffixIcon: IconButton(
icon: Icon(
controller.isPasswordHidden
? Icons.visibility_off
: Icons.visibility,
color: AppColor.primaryColor,
),
onPressed: () => controller.togglePasswordVisibility(),
),
validator: (value) {
if (value == null || value.length < 6) {
return 'Password must be at least 6 characters'.tr;
}
return null;
},
),
),
const SizedBox(height: 30),
controller.isloading
? const Center(child: MyCircularProgressIndicator())
: MyElevatedButton(
title:
(isRegistration ? 'Create Account'.tr : 'Login'.tr),
onPressed: () {
if (controller.formKey.currentState!.validate()) {
if (isRegistration) {
String email = controller.emailController.text;
String uniqueId =
controller.generateUniqueIdFromEmail(email);
box.write(BoxName.driverID, uniqueId);
box.write(BoxName.emailDriver, email);
controller.loginUsingCredentialsWithoutGoogle(
controller.passwordController.text,
email,
);
} else {
// This is the flow for iOS manual login
controller.loginWithGoogleCredential(
controller.passwordController.text,
controller.emailController.text,
);
}
}
},
),
if (isRegistration) // Show back button only on the registration form
TextButton(
onPressed: () => controller.changeGoogleDashOpen(),
child: Text(
'Back to other sign-in options'.tr,
style: TextStyle(color: AppColor.primaryColor),
),
),
],
),
),
),
);
}
/// A helper method to create styled TextFormFields.
TextFormField _buildTextFormField({
required TextEditingController controller,
required String labelText,
required String hintText,
required IconData prefixIcon,
required String? Function(String?) validator,
bool obscureText = false,
Widget? suffixIcon,
TextInputType keyboardType = TextInputType.text,
}) {
return TextFormField(
controller: controller,
validator: validator,
obscureText: obscureText,
keyboardType: keyboardType,
decoration: InputDecoration(
labelText: labelText,
hintText: hintText,
prefixIcon: Icon(prefixIcon, color: AppColor.primaryColor),
suffixIcon: suffixIcon,
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12.0)),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0),
borderSide:
const BorderSide(color: AppColor.primaryColor, width: 2.0),
),
),
);
}
/// A helper for creating consistent social login buttons.
Widget _buildSocialButton({
required String text,
required IconData icon,
required Color backgroundColor,
required VoidCallback onPressed,
}) {
return ElevatedButton.icon(
icon: Icon(icon, color: Colors.white),
label:
Text(text, style: const TextStyle(color: Colors.white, fontSize: 16)),
onPressed: onPressed,
style: ElevatedButton.styleFrom(
backgroundColor: backgroundColor,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
padding: const EdgeInsets.symmetric(vertical: 14),
),
);
}
/// Redesigned UI for the Terms and Conditions agreement page.
Widget _buildAgreementPage(
BuildContext context, LoginDriverController controller) {
// This UI can be identical to the one in LoginPage for consistency.
// I am reusing the improved design from the previous request.
return Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.policy_outlined,
size: 80, color: AppColor.primaryColor),
const SizedBox(height: 20),
Text('Driver Agreement'.tr,
textAlign: TextAlign.center, style: AppStyle.headTitle2),
const SizedBox(height: 30),
RichText(
textAlign: TextAlign.center,
text: TextSpan(
style: AppStyle.title.copyWith(height: 1.5),
children: [
TextSpan(
text:
"To become a driver, you must review and agree to the "
.tr),
TextSpan(
text: 'Terms of Use'.tr,
style: const TextStyle(
decoration: TextDecoration.underline,
color: AppColor.blueColor,
fontWeight: FontWeight.bold),
recognizer: TapGestureRecognizer()
..onTap = () {
launchUrl(
Uri.parse('${AppLink.server}/privacy_policy.php'),
mode: LaunchMode.externalApplication);
}),
TextSpan(text: " and acknowledge our Privacy Policy.".tr),
],
),
),
Expanded(
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade300),
borderRadius: BorderRadius.circular(8),
),
child: SingleChildScrollView(
padding: const EdgeInsets.all(12),
child: HtmlWidget(box.read(BoxName.lang).toString() == 'ar'
? AppInformation.privacyPolicyArabic
: AppInformation.privacyPolicy),
),
),
),
CheckboxListTile(
title: Text('I Agree'.tr, style: AppStyle.title),
value: controller.isAgreeTerms,
onChanged: (value) => controller.changeAgreeTerm(),
activeColor: AppColor.primaryColor,
controlAffinity: ListTileControlAffinity.leading,
),
const SizedBox(height: 16),
SizedBox(
width: double.infinity,
child: MyElevatedButton(
title: 'Continue'.tr,
onPressed: controller.isAgreeTerms
? () => controller.saveAgreementTerms()
: () {},
),
),
],
),
);
}
/// Redesigned UI for the Location Permission request page.
Widget _buildLocationPermissionPage(
BuildContext context, LoginDriverController controller) {
return Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Icon(Icons.location_on_outlined,
size: 80, color: AppColor.primaryColor),
const SizedBox(height: 20),
Text(
'Location Access Required'.tr,
textAlign: TextAlign.center,
style: AppStyle.headTitle2,
),
const SizedBox(height: 16),
Text(
'We need access to your location to match you with nearby passengers and provide accurate navigation.'
.tr,
textAlign: TextAlign.center,
style: AppStyle.title,
),
const SizedBox(height: 24),
Text(
'Please allow location access "all the time" to receive ride requests even when the app is in the background.'
.tr,
textAlign: TextAlign.center,
style: AppStyle.title.copyWith(
color: AppColor.greenColor, fontWeight: FontWeight.bold),
),
const SizedBox(height: 40),
MyElevatedButton(
title: "Allow Location Access".tr,
onPressed: () async {
await getLocationPermission(); // Assumes this function handles the request logic
if (await Permission.location.isGranted) {
box.write(BoxName.locationPermission, 'true');
controller.update(); // Re-check conditions
}
},
kolor: AppColor.greenColor,
),
const SizedBox(height: 16),
TextButton(
onPressed: () => openAppSettings(),
child: Text("Open Settings".tr,
style: const TextStyle(color: AppColor.blueColor)),
),
],
),
);
}
}