D1APP-43 authentication (dynamic)
This commit is contained in:
parent
0e312636a7
commit
a472c97c4e
|
|
@ -1,10 +1,10 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class LightThemeConfig {
|
class LightThemeConfig {
|
||||||
static const Color _primary = Color(0XFF007EA7);
|
static const Color _primary = Color(0xFF007EA7);
|
||||||
static const Color _white = Color(0XFFFFFFFF);
|
static const Color _white = Color(0xFFFFFFFF);
|
||||||
static const Color _black = Color(0XFF292929);
|
static const Color _black = Color(0xFF292929);
|
||||||
static const Color _background = Color(0XFFF8F8FA);
|
static const Color _background = Color(0xFFF8F8FA);
|
||||||
|
|
||||||
static final ThemeData themeData = ThemeData(
|
static final ThemeData themeData = ThemeData(
|
||||||
backgroundColor: _background,
|
backgroundColor: _background,
|
||||||
|
|
@ -28,11 +28,11 @@ class LightThemeConfig {
|
||||||
static const ColorScheme _colorScheme = ColorScheme(
|
static const ColorScheme _colorScheme = ColorScheme(
|
||||||
primary: _primary,
|
primary: _primary,
|
||||||
primaryVariant: _white,
|
primaryVariant: _white,
|
||||||
secondary: Color(0XFFD61515),
|
secondary: Color(0xFFD61515),
|
||||||
secondaryVariant: _white,
|
secondaryVariant: _white,
|
||||||
surface: _white,
|
surface: _white,
|
||||||
background: _background,
|
background: _background,
|
||||||
error: Color(0XFFF00505),
|
error: Color(0xFFF00505),
|
||||||
onPrimary: _white,
|
onPrimary: _white,
|
||||||
onSecondary: _white,
|
onSecondary: _white,
|
||||||
onSurface: _black,
|
onSurface: _black,
|
||||||
|
|
@ -72,9 +72,9 @@ class LightThemeConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
class DarkThemeConfig {
|
class DarkThemeConfig {
|
||||||
static const Color _primary = Color(0XFF007EA7);
|
static const Color _primary = Color(0xFF007EA7);
|
||||||
static const Color _white = Color(0XFFFFFFFF);
|
static const Color _white = Color(0xFFFFFFFF);
|
||||||
static const Color _background = Color(0XFF202224);
|
static const Color _background = Color(0xFF202224);
|
||||||
|
|
||||||
static final ThemeData themeData = ThemeData(
|
static final ThemeData themeData = ThemeData(
|
||||||
backgroundColor: _background,
|
backgroundColor: _background,
|
||||||
|
|
@ -101,11 +101,11 @@ class DarkThemeConfig {
|
||||||
static const ColorScheme _colorScheme = ColorScheme(
|
static const ColorScheme _colorScheme = ColorScheme(
|
||||||
primary: _primary,
|
primary: _primary,
|
||||||
primaryVariant: _white,
|
primaryVariant: _white,
|
||||||
secondary: Color(0XFFE53939),
|
secondary: Color(0xFFE53939),
|
||||||
secondaryVariant: _white,
|
secondaryVariant: _white,
|
||||||
surface: Color(0XFF181B1F),
|
surface: Color(0xFF181B1F),
|
||||||
background: _background,
|
background: _background,
|
||||||
error: Color(0XFFF53B3B),
|
error: Color(0xFFF53B3B),
|
||||||
onPrimary: _white,
|
onPrimary: _white,
|
||||||
onSecondary: _white,
|
onSecondary: _white,
|
||||||
onSurface: text,
|
onSurface: text,
|
||||||
|
|
@ -144,78 +144,81 @@ class DarkThemeConfig {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Grey colors
|
// Grey colors
|
||||||
static const Color white = Color(0XFFFFFFFF);
|
static const Color white = Color(0xFFFFFFFF);
|
||||||
static const Color title = Color(0XFFF5F5F5);
|
static const Color title = Color(0xFFF5F5F5);
|
||||||
static const Color text = Color(0XFFD6D6D6);
|
static const Color text = Color(0xFFD6D6D6);
|
||||||
static const Color hint = Color(0XFFBBBBBB);
|
static const Color hint = Color(0xFFBBBBBB);
|
||||||
static const Color border = Color(0XFF666666);
|
static const Color border = Color(0xFF666666);
|
||||||
|
|
||||||
// Error and success
|
// Error and success
|
||||||
static const Color errorLight = Color(0XFFF0C9CD);
|
static const Color errorLight = Color(0xFFF0C9CD);
|
||||||
static const Color error = Color(0XFFF53B3B);
|
static const Color error = Color(0xFFF53B3B);
|
||||||
static const Color successLight = Color(0XFFBBD6B4);
|
static const Color successLight = Color(0xFFBBD6B4);
|
||||||
static const Color success = Color(0XFF32A64C);
|
static const Color success = Color(0xFF32A64C);
|
||||||
}
|
}
|
||||||
|
|
||||||
extension DidvanColorScheme on ColorScheme {
|
extension DidvanColorScheme on ColorScheme {
|
||||||
// Secondary colors
|
// Secondary colors
|
||||||
Color get secondaryDisabled => brightness == Brightness.dark
|
Color get secondaryDisabled => brightness == Brightness.dark
|
||||||
? const Color(0XFF703838)
|
? const Color(0xFF703838)
|
||||||
: const Color(0XFFFFC8C8);
|
: const Color(0xFFFFC8C8);
|
||||||
|
|
||||||
Color get white => const Color(0XFFFFFFFF);
|
Color get white => const Color(0xFFFFFFFF);
|
||||||
Color get focused => brightness == Brightness.dark
|
Color get focused => brightness == Brightness.dark
|
||||||
? const Color(0XFF323C47)
|
? const Color(0xFF323C47)
|
||||||
: const Color(0XFFE6F3FA);
|
: const Color(0xFFE6F3FA);
|
||||||
Color get navigation => brightness == Brightness.dark
|
Color get navigation => brightness == Brightness.dark
|
||||||
? const Color(0XFF181B1F)
|
? const Color(0xFF181B1F)
|
||||||
: const Color(0XFF012348);
|
: const Color(0xFF012348);
|
||||||
Color get focusedBorder => brightness == Brightness.dark
|
Color get focusedBorder => brightness == Brightness.dark
|
||||||
? const Color(0XFFC8E0F4)
|
? const Color(0xFFC8E0F4)
|
||||||
: const Color(0XFF195D80);
|
: const Color(0xFF195D80);
|
||||||
Color get title => brightness == Brightness.dark
|
Color get title => brightness == Brightness.dark
|
||||||
? const Color(0XFFD6D6D6)
|
? const Color(0xFFD6D6D6)
|
||||||
: const Color(0XFF1B3C59);
|
: const Color(0xFF1B3C59);
|
||||||
Color get text => brightness == Brightness.dark
|
Color get text => brightness == Brightness.dark
|
||||||
? const Color(0XFFD6D6D6)
|
? const Color(0xFFD6D6D6)
|
||||||
: const Color(0XFF292929);
|
: const Color(0xFF292929);
|
||||||
Color get inputText => brightness == Brightness.dark
|
Color get inputText => brightness == Brightness.dark
|
||||||
? const Color(0XFFA3A3A3)
|
? const Color(0xFFA3A3A3)
|
||||||
: const Color(0XFF3D3D3D);
|
: const Color(0xFF3D3D3D);
|
||||||
Color get caption => brightness == Brightness.dark
|
Color get caption => brightness == Brightness.dark
|
||||||
? const Color(0XFFBBBBBB)
|
? const Color(0xFFBBBBBB)
|
||||||
: const Color(0XFF666666);
|
: const Color(0xFF666666);
|
||||||
Color get hint => const Color(0XFFBBBBBB);
|
Color get hint => const Color(0xFFBBBBBB);
|
||||||
Color get disabledText => brightness == Brightness.dark
|
Color get disabledText => brightness == Brightness.dark
|
||||||
? const Color(0XFF666666)
|
? const Color(0xFF666666)
|
||||||
: const Color(0XFFE0E0E0);
|
: const Color(0xFFE0E0E0);
|
||||||
Color get border => brightness == Brightness.dark
|
Color get border => brightness == Brightness.dark
|
||||||
? const Color(0XFF666666)
|
? const Color(0xFF666666)
|
||||||
: const Color(0XFFE0E0E0);
|
: const Color(0xFFE0E0E0);
|
||||||
Color get cardBorder => brightness == Brightness.dark
|
Color get cardBorder => brightness == Brightness.dark
|
||||||
? const Color(0XFF666666)
|
? const Color(0xFF666666)
|
||||||
: const Color(0XFFEBEBEB);
|
: const Color(0xFFEBEBEB);
|
||||||
Color get disabledBackground => brightness == Brightness.dark
|
Color get disabledBackground => brightness == Brightness.dark
|
||||||
? const Color(0XFF1F1F1F)
|
? const Color(0xFF1F1F1F)
|
||||||
: const Color(0XFFE0E0E0);
|
: const Color(0xFFE0E0E0);
|
||||||
Color get secondCTA => brightness == Brightness.dark
|
Color get secondCTA => brightness == Brightness.dark
|
||||||
? const Color(0XFF474747)
|
? const Color(0xFF474747)
|
||||||
: const Color(0XFFF5F5F5);
|
: const Color(0xFFF5F5F5);
|
||||||
Color get splash => brightness == Brightness.dark
|
Color get splash => brightness == Brightness.dark
|
||||||
? const Color(0XFF333333)
|
? const Color(0xFF333333)
|
||||||
: const Color(0XFFC8E0F4);
|
: const Color(0xFFC8E0F4);
|
||||||
Color get black => brightness == Brightness.dark
|
Color get black => brightness == Brightness.dark
|
||||||
? const Color(0XFF1F1F1F)
|
? const Color(0xFF1F1F1F)
|
||||||
: const Color(0XFF292929);
|
: const Color(0xFF292929);
|
||||||
|
Color get overlay => brightness == Brightness.dark
|
||||||
|
? const Color(0xFF0F1011)
|
||||||
|
: const Color(0xFF292929);
|
||||||
|
|
||||||
// Error and success colors
|
// Error and success colors
|
||||||
Color get errorLight => brightness == Brightness.dark
|
Color get errorLight => brightness == Brightness.dark
|
||||||
? const Color(0XFFF0C9CD)
|
? const Color(0xFFF0C9CD)
|
||||||
: const Color(0XFFFFF8F8);
|
: const Color(0xFFFFF8F8);
|
||||||
Color get successLight => brightness == Brightness.dark
|
Color get successLight => brightness == Brightness.dark
|
||||||
? const Color(0XFFBBD6B4)
|
? const Color(0xFFBBD6B4)
|
||||||
: const Color(0XFFF5FFFC);
|
: const Color(0xFFF5FFFC);
|
||||||
Color get success => brightness == Brightness.dark
|
Color get success => brightness == Brightness.dark
|
||||||
? const Color(0XFF32A64C)
|
? const Color(0xFF32A64C)
|
||||||
: const Color(0XFF2BB24A);
|
: const Color(0xFF2BB24A);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
enum AppState {
|
enum AppState {
|
||||||
idle,
|
idle,
|
||||||
busy,
|
busy,
|
||||||
|
isolatedBusy,
|
||||||
failed,
|
failed,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AlertData {
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
AlertData({required this.message});
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:didvan/config/design_config.dart';
|
import 'package:didvan/config/design_config.dart';
|
||||||
import 'package:didvan/pages/authentication/authentication_state.dart';
|
import 'package:didvan/pages/authentication/authentication_state.dart';
|
||||||
import 'package:didvan/pages/authentication/screens/password.dart';
|
import 'package:didvan/pages/authentication/screens/password.dart';
|
||||||
import 'package:didvan/pages/authentication/screens/phone_number.dart';
|
import 'package:didvan/pages/authentication/screens/username.dart';
|
||||||
import 'package:didvan/pages/authentication/screens/reset_password.dart';
|
import 'package:didvan/pages/authentication/screens/reset_password.dart';
|
||||||
import 'package:didvan/pages/authentication/screens/verification.dart';
|
import 'package:didvan/pages/authentication/screens/verification.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
@ -16,7 +16,7 @@ class Authentication extends StatefulWidget {
|
||||||
|
|
||||||
class _AuthenticationState extends State<Authentication> {
|
class _AuthenticationState extends State<Authentication> {
|
||||||
final List<Widget> _pages = const [
|
final List<Widget> _pages = const [
|
||||||
PhoneNumberInput(),
|
UsernameInput(),
|
||||||
PasswordInput(),
|
PasswordInput(),
|
||||||
Verification(),
|
Verification(),
|
||||||
ResetPassword(),
|
ResetPassword(),
|
||||||
|
|
@ -26,11 +26,20 @@ class _AuthenticationState extends State<Authentication> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Consumer<AuthenticationState>(
|
body: Consumer<AuthenticationState>(
|
||||||
builder: (context, state, child) => AnimatedSwitcher(
|
builder: (context, state, child) => WillPopScope(
|
||||||
|
onWillPop: () async {
|
||||||
|
if (state.currentPageIndex == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
state.currentPageIndex--;
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
child: AnimatedSwitcher(
|
||||||
duration: DesignConfig.mediumAnimationDuration,
|
duration: DesignConfig.mediumAnimationDuration,
|
||||||
child: _pages[state.currentPageIndex],
|
child: _pages[state.currentPageIndex],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,13 @@
|
||||||
|
import 'package:didvan/models/enums.dart';
|
||||||
|
import 'package:didvan/models/view/alert_data.dart';
|
||||||
import 'package:didvan/providers/core_provider.dart';
|
import 'package:didvan/providers/core_provider.dart';
|
||||||
|
import 'package:didvan/services/network/request.dart';
|
||||||
|
import 'package:didvan/services/network/request_helper.dart';
|
||||||
|
import 'package:didvan/utils/actions_sheet.dart';
|
||||||
|
|
||||||
class AuthenticationState extends CoreProvier {
|
class AuthenticationState extends CoreProvier {
|
||||||
int _currentPageIndex = 0;
|
int _currentPageIndex = 0;
|
||||||
String phoneNumber = '';
|
String username = '';
|
||||||
String password = '';
|
String password = '';
|
||||||
String verificationCode = '';
|
String verificationCode = '';
|
||||||
|
|
||||||
|
|
@ -12,4 +17,38 @@ class AuthenticationState extends CoreProvier {
|
||||||
}
|
}
|
||||||
|
|
||||||
int get currentPageIndex => _currentPageIndex;
|
int get currentPageIndex => _currentPageIndex;
|
||||||
|
|
||||||
|
Future<void> confirmUsername() async {
|
||||||
|
appState = AppState.isolatedBusy;
|
||||||
|
final RequestService service = RequestService(
|
||||||
|
RequestHelper.confirmUsername,
|
||||||
|
useAutherization: false,
|
||||||
|
body: {'username': username},
|
||||||
|
);
|
||||||
|
await service.post();
|
||||||
|
if (service.isSuccess && service.result['confirmed']) {
|
||||||
|
appState = AppState.idle;
|
||||||
|
currentPageIndex++;
|
||||||
|
} else {
|
||||||
|
appState = AppState.failed;
|
||||||
|
ActionSheetUtils.showAlert(AlertData(message: service.errorMessage));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String?> login() async {
|
||||||
|
appState = AppState.isolatedBusy;
|
||||||
|
final RequestService service = RequestService(
|
||||||
|
RequestHelper.login,
|
||||||
|
useAutherization: false,
|
||||||
|
body: {'username': username, "password": password},
|
||||||
|
);
|
||||||
|
await service.post();
|
||||||
|
if (service.isSuccess && service.result['loggedIn']) {
|
||||||
|
appState = AppState.idle;
|
||||||
|
return service.result['token'];
|
||||||
|
} else {
|
||||||
|
appState = AppState.failed;
|
||||||
|
ActionSheetUtils.showAlert(AlertData(message: service.errorMessage));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,43 @@
|
||||||
import 'package:didvan/pages/authentication/authentication_state.dart';
|
import 'package:didvan/pages/authentication/authentication_state.dart';
|
||||||
import 'package:didvan/pages/authentication/widgets/authentication_layout.dart';
|
import 'package:didvan/pages/authentication/widgets/authentication_layout.dart';
|
||||||
|
import 'package:didvan/providers/user_provider.dart';
|
||||||
|
import 'package:didvan/routes/routes.dart';
|
||||||
|
import 'package:didvan/services/network/request.dart';
|
||||||
import 'package:didvan/widgets/didvan/button.dart';
|
import 'package:didvan/widgets/didvan/button.dart';
|
||||||
import 'package:didvan/widgets/didvan/text.dart';
|
import 'package:didvan/widgets/didvan/text.dart';
|
||||||
import 'package:didvan/widgets/didvan/text_field.dart';
|
import 'package:didvan/widgets/didvan/text_field.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class PasswordInput extends StatelessWidget {
|
class PasswordInput extends StatefulWidget {
|
||||||
const PasswordInput({Key? key}) : super(key: key);
|
const PasswordInput({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PasswordInput> createState() => _PasswordInputState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PasswordInputState extends State<PasswordInput> {
|
||||||
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final AuthenticationState state = context.read<AuthenticationState>();
|
final AuthenticationState state = context.read<AuthenticationState>();
|
||||||
return AuthenticationLayout(
|
return AuthenticationLayout(
|
||||||
appBarTitle: 'ورود با شماره موبایل ' + state.phoneNumber,
|
appBarTitle:
|
||||||
|
'ورود با ${state.username.contains('09') ? 'شماره موبایل' : 'نام کاربری'} ${state.username}',
|
||||||
children: [
|
children: [
|
||||||
DidvanTextField(
|
Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: DidvanTextField(
|
||||||
onChanged: (value) => state.password = value,
|
onChanged: (value) => state.password = value,
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
title: 'کلمه عبور',
|
title: 'کلمه عبور',
|
||||||
hintText: 'کلمه عبور',
|
hintText: 'کلمه عبور',
|
||||||
obsecureText: true,
|
obsecureText: true,
|
||||||
|
validator: (value) => value!.length < 8
|
||||||
|
? 'کلمه عبور نمیتواند از 8 کاراکتر کمتر باشد'
|
||||||
|
: null,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 32,
|
height: 32,
|
||||||
|
|
@ -35,7 +52,7 @@ class PasswordInput extends StatelessWidget {
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
DidvanButton(
|
DidvanButton(
|
||||||
onPressed: () {},
|
onPressed: () => _onPressed(context),
|
||||||
title: 'ورود',
|
title: 'ورود',
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
|
|
@ -44,4 +61,18 @@ class PasswordInput extends StatelessWidget {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _onPressed(BuildContext context) async {
|
||||||
|
if (!_formKey.currentState!.validate()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final state = context.read<AuthenticationState>();
|
||||||
|
final token = await state.login();
|
||||||
|
if (token != null) {
|
||||||
|
final userProvider = context.read<UserProvider>();
|
||||||
|
await userProvider.setAndGetToken(token: token);
|
||||||
|
RequestService.token = token;
|
||||||
|
Navigator.of(context).pushReplacementNamed(Routes.home);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class PhoneNumberInput extends StatelessWidget {
|
class UsernameInput extends StatelessWidget {
|
||||||
const PhoneNumberInput({
|
const UsernameInput({
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
|
|
@ -17,12 +17,15 @@ class PhoneNumberInput extends StatelessWidget {
|
||||||
return AuthenticationLayout(
|
return AuthenticationLayout(
|
||||||
children: [
|
children: [
|
||||||
DidvanTextField(
|
DidvanTextField(
|
||||||
title: 'شماره موبایل',
|
initialValue: state.username,
|
||||||
textInputType: TextInputType.phone,
|
title: 'نام کاربری یا شماره موبایل',
|
||||||
hintText: 'شماره موبایل',
|
hintText: 'نام کاربری یا شماره موبایل',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
validator: (value) => value!.length < 4
|
||||||
|
? 'نام کاربری نمیتواند از 4 کاراکتر کوچکتر باشد'
|
||||||
|
: null,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
state.phoneNumber = value;
|
state.username = value;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
|
|
@ -30,9 +33,7 @@ class PhoneNumberInput extends StatelessWidget {
|
||||||
),
|
),
|
||||||
DidvanButton(
|
DidvanButton(
|
||||||
title: 'ورود',
|
title: 'ورود',
|
||||||
onPressed: () {
|
onPressed: state.confirmUsername,
|
||||||
state.currentPageIndex = 1;
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
Padding(
|
Padding(
|
||||||
|
|
@ -26,7 +26,7 @@ class Verification extends StatelessWidget {
|
||||||
height: 8,
|
height: 8,
|
||||||
),
|
),
|
||||||
DidvanText(
|
DidvanText(
|
||||||
state.phoneNumber,
|
state.username,
|
||||||
style: Theme.of(context).textTheme.subtitle1,
|
style: Theme.of(context).textTheme.subtitle1,
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
|
|
@ -65,7 +65,7 @@ class Verification extends StatelessWidget {
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
state.currentPageIndex++;
|
state.currentPageIndex++;
|
||||||
},
|
},
|
||||||
title: 'تایید',
|
title: 'ارسال مجدد کد',
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 48,
|
height: 48,
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ class AuthenticationLayout extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: MediaQuery.of(context).size.height,
|
height: MediaQuery.of(context).size.height,
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|
@ -34,7 +33,9 @@ class AuthenticationLayout extends StatelessWidget {
|
||||||
right: 100,
|
right: 100,
|
||||||
bottom: 40,
|
bottom: 40,
|
||||||
),
|
),
|
||||||
child: DidvanVerticalLogo(),
|
child: DidvanVerticalLogo(
|
||||||
|
height: 200,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
...children,
|
...children,
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:didvan/config/design_config.dart';
|
import 'package:didvan/config/design_config.dart';
|
||||||
import 'package:didvan/main.dart';
|
import 'package:didvan/main.dart';
|
||||||
import 'package:didvan/providers/theme_provider.dart';
|
import 'package:didvan/providers/theme_provider.dart';
|
||||||
|
import 'package:didvan/providers/user_provider.dart';
|
||||||
import 'package:didvan/routes/routes.dart';
|
import 'package:didvan/routes/routes.dart';
|
||||||
import 'package:didvan/services/app_initalizer.dart';
|
import 'package:didvan/services/app_initalizer.dart';
|
||||||
import 'package:didvan/utils/actions_sheet.dart';
|
import 'package:didvan/utils/actions_sheet.dart';
|
||||||
|
|
@ -36,8 +37,11 @@ class _SplashState extends State<Splash> {
|
||||||
_isGettingThemeData = false;
|
_isGettingThemeData = false;
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
final String? token = await context.read<UserProvider>().setAndGetToken();
|
||||||
await Future.delayed(const Duration(seconds: 2));
|
await Future.delayed(const Duration(seconds: 2));
|
||||||
Navigator.of(context).pushReplacementNamed(Routes.home);
|
Navigator.of(context).pushReplacementNamed(
|
||||||
|
token == null ? Routes.authenticaion : Routes.home,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,17 @@
|
||||||
import 'package:didvan/models/enums.dart';
|
import 'package:didvan/models/enums.dart';
|
||||||
|
import 'package:didvan/utils/actions_sheet.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
class CoreProvier with ChangeNotifier {
|
class CoreProvier with ChangeNotifier {
|
||||||
AppState _appState = AppState.idle;
|
AppState _appState = AppState.idle;
|
||||||
|
|
||||||
set appState(AppState newState) {
|
set appState(AppState newState) {
|
||||||
|
if (newState == AppState.isolatedBusy) {
|
||||||
|
ActionSheetUtils.showLogoLoadingIndicator();
|
||||||
|
}
|
||||||
|
if (_appState == AppState.isolatedBusy) {
|
||||||
|
ActionSheetUtils.pop();
|
||||||
|
}
|
||||||
_appState = newState;
|
_appState = newState;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,13 @@
|
||||||
import 'package:didvan/providers/core_provider.dart';
|
import 'package:didvan/providers/core_provider.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
|
||||||
class UserProvider extends CoreProvier {}
|
class UserProvider extends CoreProvier {
|
||||||
|
Future<String?> setAndGetToken({String? token}) async {
|
||||||
|
final box = await Hive.openBox('autherization');
|
||||||
|
if (token != null) {
|
||||||
|
await box.put('token', token);
|
||||||
|
} else {
|
||||||
|
return box.toMap()['token'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@ class RequestService {
|
||||||
Map get result => _body['result'] ?? const {};
|
Map get result => _body['result'] ?? const {};
|
||||||
Map get errors => _body['errors'] ?? const {};
|
Map get errors => _body['errors'] ?? const {};
|
||||||
|
|
||||||
String? errorMessage;
|
String errorMessage =
|
||||||
|
'خطا! لطفا اتصال اینترنت خود را بررسی و مجددا تلاش نمایید.';
|
||||||
|
|
||||||
dynamic _body;
|
dynamic _body;
|
||||||
final Map<String, String> _headers = {
|
final Map<String, String> _headers = {
|
||||||
|
|
@ -150,7 +151,7 @@ class RequestService {
|
||||||
_body = json.decode(response.body);
|
_body = json.decode(response.body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
errorMessage = _errorMessageGenerator();
|
errorMessage = _errorMessageGenerator(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _handleError(http.Response? response) {
|
bool _handleError(http.Response? response) {
|
||||||
|
|
@ -162,8 +163,8 @@ class RequestService {
|
||||||
isSuccess = false;
|
isSuccess = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (response.statusCode != 200 && response.statusCode != 204) {
|
if (response.statusCode != 200) {
|
||||||
String data;
|
dynamic data;
|
||||||
if (response.body.isEmpty) {
|
if (response.body.isEmpty) {
|
||||||
data = 'No results!';
|
data = 'No results!';
|
||||||
} else if (response.body.contains('<!DOCTYPE html>')) {
|
} else if (response.body.contains('<!DOCTYPE html>')) {
|
||||||
|
|
@ -182,9 +183,15 @@ class RequestService {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _errorMessageGenerator() {
|
String _errorMessageGenerator(http.Response? response) {
|
||||||
return isSuccess
|
String? error;
|
||||||
? result['msg']
|
if (response != null) {
|
||||||
: 'خطا! لطفا اتصال اینترنت خود را بررسی و مجددا تلاش نمایید.';
|
if (!response.body.contains('<!DOCTYPE html>')) {
|
||||||
|
if (result.isNotEmpty) {
|
||||||
|
error = result['msg'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return error ?? 'خطا! لطفا اتصال اینترنت خود را بررسی و مجددا تلاش نمایید.';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
|
import 'package:another_flushbar/flushbar.dart';
|
||||||
import 'package:didvan/config/design_config.dart';
|
import 'package:didvan/config/design_config.dart';
|
||||||
import 'package:didvan/config/theme_data.dart';
|
import 'package:didvan/config/theme_data.dart';
|
||||||
import 'package:didvan/constants/assets.dart';
|
import 'package:didvan/constants/assets.dart';
|
||||||
import 'package:didvan/models/enums.dart';
|
import 'package:didvan/models/enums.dart';
|
||||||
import 'package:didvan/models/view/action_sheet_data.dart';
|
import 'package:didvan/models/view/action_sheet_data.dart';
|
||||||
|
import 'package:didvan/models/view/alert_data.dart';
|
||||||
import 'package:didvan/widgets/didvan/button.dart';
|
import 'package:didvan/widgets/didvan/button.dart';
|
||||||
import 'package:didvan/widgets/didvan/text.dart';
|
import 'package:didvan/widgets/didvan/text.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
@ -15,13 +17,15 @@ class ActionSheetUtils {
|
||||||
static Future<void> showLogoLoadingIndicator() async {
|
static Future<void> showLogoLoadingIndicator() async {
|
||||||
await showDialog(
|
await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => _customSystemOverlayStyle(
|
builder: (context) =>
|
||||||
child: Padding(
|
// _customSystemOverlayStyle(
|
||||||
|
// child:
|
||||||
|
Padding(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
horizontal: MediaQuery.of(context).size.width / 3,
|
horizontal: MediaQuery.of(context).size.width / 3,
|
||||||
),
|
),
|
||||||
child: const RiveAnimation.asset(Assets.logoLoadingAnimation),
|
child: const RiveAnimation.asset(Assets.logoLoadingAnimation),
|
||||||
),
|
// ),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -29,12 +33,29 @@ class ActionSheetUtils {
|
||||||
static AnnotatedRegion _customSystemOverlayStyle({required Widget child}) {
|
static AnnotatedRegion _customSystemOverlayStyle({required Widget child}) {
|
||||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||||
value: DesignConfig.systemUiOverlayStyle.copyWith(
|
value: DesignConfig.systemUiOverlayStyle.copyWith(
|
||||||
// systemNavigationBarColor: Colors.black45,
|
systemNavigationBarColor: DesignConfig
|
||||||
|
.systemUiOverlayStyle.systemNavigationBarColor!
|
||||||
|
.withBlue(20),
|
||||||
),
|
),
|
||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<void> showAlert(AlertData alertData) async {
|
||||||
|
await Flushbar(
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
message: alertData.message,
|
||||||
|
backgroundColor: Theme.of(context).colorScheme.focused,
|
||||||
|
borderRadius: DesignConfig.mediumBorderRadius,
|
||||||
|
messageColor: Theme.of(context).colorScheme.text,
|
||||||
|
flushbarPosition: FlushbarPosition.TOP,
|
||||||
|
duration: const Duration(seconds: 2),
|
||||||
|
boxShadows: [
|
||||||
|
BoxShadow(color: Theme.of(context).colorScheme.cardBorder),
|
||||||
|
],
|
||||||
|
).show(context);
|
||||||
|
}
|
||||||
|
|
||||||
static Future<void> showBottomSheet({required ActionSheetData data}) async {
|
static Future<void> showBottomSheet({required ActionSheetData data}) async {
|
||||||
await showModalBottomSheet(
|
await showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
|
|
@ -103,4 +124,9 @@ class ActionSheetUtils {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pop() {
|
||||||
|
DesignConfig.updateSystemUiOverlayStyle();
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,10 @@ class DidvanButton extends StatelessWidget {
|
||||||
),
|
),
|
||||||
height: 48,
|
height: 48,
|
||||||
color: Theme.of(context).colorScheme.primary,
|
color: Theme.of(context).colorScheme.primary,
|
||||||
onPressed: onPressed,
|
onPressed: () {
|
||||||
|
FocusScope.of(context).unfocus();
|
||||||
|
onPressed?.call();
|
||||||
|
},
|
||||||
child: _childBuilder(),
|
child: _childBuilder(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import 'package:didvan/config/design_config.dart';
|
import 'package:didvan/config/design_config.dart';
|
||||||
import 'package:didvan/config/theme_data.dart';
|
import 'package:didvan/config/theme_data.dart';
|
||||||
|
import 'package:didvan/constants/app_icons.dart';
|
||||||
|
import 'package:didvan/widgets/animated_visibility.dart';
|
||||||
import 'package:didvan/widgets/didvan/text.dart';
|
import 'package:didvan/widgets/didvan/text.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
@ -36,11 +38,14 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
|
||||||
final FocusNode _focusNode = FocusNode();
|
final FocusNode _focusNode = FocusNode();
|
||||||
final TextEditingController _controller = TextEditingController();
|
final TextEditingController _controller = TextEditingController();
|
||||||
|
|
||||||
bool _hasError = false;
|
|
||||||
bool _hideContent = false;
|
bool _hideContent = false;
|
||||||
|
String? _error;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
if (widget.initialValue != null) {
|
||||||
|
_controller.text = widget.initialValue;
|
||||||
|
}
|
||||||
_hideContent = widget.obsecureText;
|
_hideContent = widget.obsecureText;
|
||||||
_focusNode.addListener(() {
|
_focusNode.addListener(() {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
|
|
@ -57,7 +62,7 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
|
||||||
if (widget.title != null)
|
if (widget.title != null)
|
||||||
DidvanText(
|
DidvanText(
|
||||||
widget.title!,
|
widget.title!,
|
||||||
color: !widget.enabled ? Theme.of(context).colorScheme.hint : null,
|
color: _titleColor(),
|
||||||
),
|
),
|
||||||
if (widget.title != null) const SizedBox(height: 8),
|
if (widget.title != null) const SizedBox(height: 8),
|
||||||
Container(
|
Container(
|
||||||
|
|
@ -85,6 +90,7 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
|
||||||
enabled: widget.enabled,
|
enabled: widget.enabled,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
hintText: widget.hintText,
|
hintText: widget.hintText,
|
||||||
|
errorStyle: const TextStyle(height: 0),
|
||||||
hintStyle: Theme.of(context)
|
hintStyle: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodyText2!
|
.bodyText2!
|
||||||
|
|
@ -92,6 +98,24 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
AnimatedVisibility(
|
||||||
|
isVisible: _error != null,
|
||||||
|
duration: DesignConfig.lowAnimationDuration,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
DidvanIcons.lightbulb_exclamation_regular,
|
||||||
|
color: Theme.of(context).colorScheme.error,
|
||||||
|
size: 14,
|
||||||
|
),
|
||||||
|
DidvanText(
|
||||||
|
_error ?? '',
|
||||||
|
style: Theme.of(context).textTheme.caption,
|
||||||
|
color: Theme.of(context).colorScheme.error,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
))
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -99,12 +123,21 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
|
||||||
Color _borderColor() {
|
Color _borderColor() {
|
||||||
if (_focusNode.hasFocus) {
|
if (_focusNode.hasFocus) {
|
||||||
return Theme.of(context).colorScheme.primary;
|
return Theme.of(context).colorScheme.primary;
|
||||||
} else if (_hasError) {
|
} else if (_error != null) {
|
||||||
return Theme.of(context).colorScheme.error;
|
return Theme.of(context).colorScheme.error;
|
||||||
}
|
}
|
||||||
return Theme.of(context).colorScheme.border;
|
return Theme.of(context).colorScheme.border;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Color? _titleColor() {
|
||||||
|
if (!widget.enabled) {
|
||||||
|
return Theme.of(context).colorScheme.hint;
|
||||||
|
}
|
||||||
|
if (_error != null) {
|
||||||
|
return Theme.of(context).colorScheme.error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Color _fillColor() {
|
Color _fillColor() {
|
||||||
if (!widget.enabled) {
|
if (!widget.enabled) {
|
||||||
return Theme.of(context).colorScheme.secondCTA;
|
return Theme.of(context).colorScheme.secondCTA;
|
||||||
|
|
@ -112,7 +145,7 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
|
||||||
if (_focusNode.hasFocus) {
|
if (_focusNode.hasFocus) {
|
||||||
return Theme.of(context).colorScheme.focused;
|
return Theme.of(context).colorScheme.focused;
|
||||||
}
|
}
|
||||||
if (_hasError) {
|
if (_error != null) {
|
||||||
return Theme.of(context).colorScheme.errorLight;
|
return Theme.of(context).colorScheme.errorLight;
|
||||||
}
|
}
|
||||||
return Theme.of(context).colorScheme.surface;
|
return Theme.of(context).colorScheme.surface;
|
||||||
|
|
@ -129,7 +162,9 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: Icon(
|
child: Icon(
|
||||||
_hideContent ? Icons.remove_red_eye : Icons.remove_red_eye_outlined,
|
_hideContent
|
||||||
|
? DidvanIcons.eye_regular
|
||||||
|
: DidvanIcons.eye_slash_regular,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
@ -143,6 +178,18 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
|
||||||
}
|
}
|
||||||
|
|
||||||
String? _validator(String? value) {
|
String? _validator(String? value) {
|
||||||
_hasError = false;
|
if (widget.validator != null) {
|
||||||
|
final String? error = widget.validator!(value);
|
||||||
|
if (error != null) {
|
||||||
|
setState(() {
|
||||||
|
_error = error;
|
||||||
|
});
|
||||||
|
return '';
|
||||||
|
} else {
|
||||||
|
setState(() {
|
||||||
|
_error = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,11 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
|
||||||
class DidvanVerticalLogo extends StatelessWidget {
|
class DidvanVerticalLogo extends StatelessWidget {
|
||||||
const DidvanVerticalLogo({Key? key}) : super(key: key);
|
final double? height;
|
||||||
|
const DidvanVerticalLogo({Key? key, this.height}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SvgPicture.asset(Assets.verticalLogoWithText);
|
return SvgPicture.asset(Assets.verticalLogoWithText, height: height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
# Generated by pub
|
# Generated by pub
|
||||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||||
packages:
|
packages:
|
||||||
|
another_flushbar:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: another_flushbar
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.10.28"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ dependencies:
|
||||||
just_audio: ^0.9.18
|
just_audio: ^0.9.18
|
||||||
record_web: ^0.2.1
|
record_web: ^0.2.1
|
||||||
just_waveform: ^0.0.1
|
just_waveform: ^0.0.1
|
||||||
|
another_flushbar: ^1.10.28
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue