marco.pms.mobileapp/lib/view/auth/login_option_screen.dart
Vaibhav Surve 25dfcf3e08 feat: Add MPIN authentication and OTP login screens
- Implemented MPINAuthScreen for generating and entering MPIN.
- Created MPINScreen for user interaction with MPIN input.
- Developed OTPLoginScreen for OTP verification process.
- Added request demo bottom sheet with organization form.
- Enhanced DashboardScreen to check MPIN status and prompt user to generate MPIN if not set.
2025-06-10 10:04:18 +05:30

226 lines
6.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_lucide/flutter_lucide.dart';
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
import 'package:marco/images.dart';
import 'package:marco/view/auth/email_login_form.dart';
import 'package:marco/view/auth/otp_login_form.dart';
import 'package:marco/helpers/services/api_endpoints.dart';
import 'package:marco/helpers/widgets/my_text.dart'; // Make sure this import is added
enum LoginOption { email, otp }
class LoginOptionScreen extends StatefulWidget {
const LoginOptionScreen({super.key});
@override
State<LoginOptionScreen> createState() => _LoginOptionScreenState();
}
class _LoginOptionScreenState extends State<LoginOptionScreen> with UIMixin {
LoginOption _selectedOption = LoginOption.email;
bool get _isBetaEnvironment => ApiEndpoints.baseUrl.contains("stage");
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: contentTheme.brandRed,
body: SafeArea(
child: LayoutBuilder(
builder: (context, constraints) {
return Column(
children: [
const SizedBox(height: 24),
_buildHeader(),
const SizedBox(height: 16),
_buildWelcomeTextsAndChips(),
const SizedBox(height: 16),
Expanded(
child: Container(
width: double.infinity,
decoration: const BoxDecoration(
color: Colors.white,
borderRadius:
BorderRadius.vertical(top: Radius.circular(32)),
),
child: SingleChildScrollView(
padding: const EdgeInsets.symmetric(
horizontal: 20, vertical: 24),
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraints.maxHeight - 200,
),
child: IntrinsicHeight(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildLoginForm(),
const SizedBox(height: 24),
const SizedBox(height: 8),
Center(child: _buildVersionInfo()),
],
),
),
),
),
),
),
],
);
},
),
),
);
}
Widget _buildHeader() {
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 6,
offset: Offset(0, 3),
)
],
),
child: Image.asset(Images.logoDark, height: 70),
);
}
Widget _buildBetaLabel() {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(
color: Colors.orangeAccent,
borderRadius: BorderRadius.circular(4),
),
child: MyText(
'BETA',
color: Colors.white,
fontWeight: 600,
fontSize: 12,
),
);
}
Widget _buildLoginOptionChips() {
return Wrap(
spacing: 12,
runSpacing: 8,
alignment: WrapAlignment.center,
children: [
_buildOptionChip(
title: "User Name",
icon: LucideIcons.mail,
value: LoginOption.email,
),
_buildOptionChip(
title: "OTP",
icon: LucideIcons.message_square,
value: LoginOption.otp,
),
],
);
}
Widget _buildWelcomeTextsAndChips() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
children: [
MyText(
"Welcome to Marco",
fontSize: 20,
fontWeight: 700,
color: Colors.white,
textAlign: TextAlign.center,
),
const SizedBox(height: 4),
MyText(
"Streamline Project Management and Boost Productivity with Automation.",
fontSize: 14,
color: Colors.white70,
textAlign: TextAlign.center,
),
if (_isBetaEnvironment) ...[
const SizedBox(height: 8),
_buildBetaLabel(),
],
const SizedBox(height: 20),
_buildLoginOptionChips(),
],
),
);
}
Widget _buildOptionChip({
required String title,
required IconData icon,
required LoginOption value,
}) {
final bool isSelected = _selectedOption == value;
final Color selectedTextColor = contentTheme.brandRed;
final Color unselectedTextColor = Colors.white;
final Color selectedBgColor = Colors.grey[100]!;
final Color unselectedBgColor = contentTheme.brandRed;
return ChoiceChip(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
label: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
icon,
size: 18,
color: isSelected ? selectedTextColor : unselectedTextColor,
),
const SizedBox(width: 6),
MyText(
title,
fontSize: 14,
fontWeight: 600,
color: isSelected ? selectedTextColor : unselectedTextColor,
),
],
),
selected: isSelected,
onSelected: (_) => setState(() => _selectedOption = value),
selectedColor: selectedBgColor,
backgroundColor: unselectedBgColor,
side: BorderSide(
color: Colors.white.withOpacity(0.6),
width: 1.2,
),
elevation: 3,
shadowColor: Colors.black12,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
);
}
Widget _buildLoginForm() {
switch (_selectedOption) {
case LoginOption.email:
return EmailLoginForm();
case LoginOption.otp:
return const OTPLoginScreen();
}
}
Widget _buildVersionInfo() {
return Padding(
padding: const EdgeInsets.only(bottom: 8),
child: MyText(
'App version 1.0.0',
color: Colors.grey.shade500,
fontSize: 12,
),
);
}
}