diff --git a/lib/assets/fonts/dana-fa.ttf b/lib/assets/fonts/dana-fa.ttf new file mode 100644 index 0000000..3691b96 Binary files /dev/null and b/lib/assets/fonts/dana-fa.ttf differ diff --git a/lib/assets/fonts/dana.ttf b/lib/assets/fonts/dana.ttf new file mode 100644 index 0000000..93200a1 Binary files /dev/null and b/lib/assets/fonts/dana.ttf differ diff --git a/lib/assets/images/logo/logo-h-t.png b/lib/assets/images/logo/logo-h-t.png new file mode 100644 index 0000000..0c6623e Binary files /dev/null and b/lib/assets/images/logo/logo-h-t.png differ diff --git a/lib/assets/images/logo/logo-v-t.png b/lib/assets/images/logo/logo-v-t.png new file mode 100644 index 0000000..c45a614 Binary files /dev/null and b/lib/assets/images/logo/logo-v-t.png differ diff --git a/lib/assets/logo/logo-t-d.png b/lib/assets/logo/logo-t-d.png deleted file mode 100644 index 0be1b86..0000000 Binary files a/lib/assets/logo/logo-t-d.png and /dev/null differ diff --git a/lib/config/design_config.dart b/lib/config/design_config.dart index d79f281..5c6d595 100644 --- a/lib/config/design_config.dart +++ b/lib/config/design_config.dart @@ -1,11 +1,23 @@ import 'package:flutter/material.dart'; class DesignConfig { + static const Color lightPrimaryColor3 = Color(0XFFF5FAFC); static const Color primaryColor = Color(0XFF007EA7); + static const Color darkPrimaryColor2 = Color(0XFF1B3C59); + + static const Color greyColor4 = Color(0XFFE0E0E0); + static const Color greyColor5 = Color(0XFFE0E0E0); + + static const Color lightRedColor = Color(0XFFFFF8F8); static final ThemeData lightTheme = ThemeData( primaryColor: primaryColor, colorScheme: lightColorScheme, + fontFamily: 'dana-fa', + textTheme: const TextTheme( + bodyText1: body1TextStyle, + caption: captionTextStyle, + ), ); static const ColorScheme lightColorScheme = ColorScheme( @@ -23,4 +35,18 @@ class DesignConfig { onError: Colors.white, brightness: Brightness.light, ); + + static const TextStyle body1TextStyle = TextStyle( + fontSize: 14, + ); + static const TextStyle captionTextStyle = TextStyle( + fontSize: 13, + ); + + static const BorderRadius lowBorderRadius = BorderRadius.all( + Radius.circular(8), + ); + static final Border lightBorder = Border.all(color: DesignConfig.greyColor4); + + static const Duration defaultAppDuration = Duration(milliseconds: 400); } diff --git a/lib/constants/assets.dart b/lib/constants/assets.dart index e28d363..f4f2a00 100644 --- a/lib/constants/assets.dart +++ b/lib/constants/assets.dart @@ -1,4 +1,9 @@ class Assets { static const String _basePath = 'lib/assets'; - static const String logoWithTitleAndDesc = _basePath + '/logo/logo-t-d.png'; + static const String _baseImagesPath = _basePath + '/images'; + + static const String verticalLogoWithText = + _baseImagesPath + '/logo/logo-v-t.png'; + static const String horizontalLogoWithText = + _baseImagesPath + '/logo/logo-h-t.png'; } diff --git a/lib/pages/authentication/authentication.dart b/lib/pages/authentication/authentication.dart new file mode 100644 index 0000000..fd92afb --- /dev/null +++ b/lib/pages/authentication/authentication.dart @@ -0,0 +1,133 @@ +import 'package:didvan/config/design_config.dart'; +import 'package:didvan/pages/authentication/authentication_state.dart'; +import 'package:didvan/pages/authentication/widgets/authentication_app_bar.dart'; +import 'package:didvan/widgets/didvan/button.dart'; +import 'package:didvan/widgets/didvan/text_field.dart'; +import 'package:didvan/widgets/logos/didvan_horizontal_logo.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class Authentication extends StatefulWidget { + const Authentication({Key? key}) : super(key: key); + + @override + State createState() => _AuthenticationState(); +} + +class _AuthenticationState extends State { + final List _pages = const [ + PhoneNumberInput(), + PasswordInput(), + ]; + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Consumer( + builder: (context, state, child) => AnimatedSwitcher( + duration: DesignConfig.defaultAppDuration, + child: _pages[state.currentPageIndex], + ), + ), + ); + } +} + +class PhoneNumberInput extends StatelessWidget { + const PhoneNumberInput({ + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final AuthenticationState state = context.read(); + return SingleChildScrollView( + physics: const NeverScrollableScrollPhysics(), + padding: const EdgeInsets.all(20), + child: SizedBox( + height: MediaQuery.of(context).size.height, + child: Column( + children: [ + const Padding( + padding: EdgeInsets.only( + top: 80, + left: 100, + right: 100, + bottom: 40, + ), + child: DidvanVerticalLogo(), + ), + DidvanTextField( + title: 'شماره موبایل', + textInputType: TextInputType.phone, + hintText: 'شماره موبایل', + onChanged: (value) { + state.phoneNumber = value; + }, + ), + const SizedBox( + height: 20, + ), + DidvanButton( + title: 'ورود', + onPressed: () { + state.currentPageIndex = 1; + }, + ), + const Spacer(), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 60), + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: Theme.of(context).textTheme.caption, + children: [ + const TextSpan(text: 'با ثبت نام و ورود به دیدوان،'), + TextSpan( + text: ' شرایط ', + style: Theme.of(context) + .textTheme + .caption! + .copyWith(color: Theme.of(context).primaryColor), + recognizer: TapGestureRecognizer() + ..onTap = () { + //TODO: Needs implementaion + }, + ), + const TextSpan(text: 'و\n'), + TextSpan( + text: ' قوانین حریم خصوصی ', + style: Theme.of(context) + .textTheme + .caption! + .copyWith(color: Theme.of(context).primaryColor), + recognizer: TapGestureRecognizer() + ..onTap = () { + //TODO: Needs implementaion + }, + ), + const TextSpan(text: 'را می‌پذیرم'), + ], + ), + ), + ), + const SizedBox( + height: 48, + ), + ], + ), + ), + ); + } +} + +class PasswordInput extends StatelessWidget { + const PasswordInput({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final AuthenticationState state = context.read(); + return Container(); + } +} diff --git a/lib/pages/authentication/authentication_state.dart b/lib/pages/authentication/authentication_state.dart new file mode 100644 index 0000000..d3975e7 --- /dev/null +++ b/lib/pages/authentication/authentication_state.dart @@ -0,0 +1,14 @@ +import 'package:didvan/providers/core_provider.dart'; + +class AuthenticationState extends CoreProvier { + int _currentPageIndex = 0; + String phoneNumber = ''; + String password = ''; + + set currentPageIndex(int value) { + _currentPageIndex = value; + notifyListeners(); + } + + int get currentPageIndex => _currentPageIndex; +} diff --git a/lib/pages/authentication/widgets/authentication_app_bar.dart b/lib/pages/authentication/widgets/authentication_app_bar.dart new file mode 100644 index 0000000..844a8ea --- /dev/null +++ b/lib/pages/authentication/widgets/authentication_app_bar.dart @@ -0,0 +1,30 @@ +import 'package:didvan/pages/authentication/authentication_state.dart'; +import 'package:didvan/widgets/didvan/text.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class AuthenticationAppBar extends StatelessWidget { + final String? title; + const AuthenticationAppBar({Key? key, this.title}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top + 12), + child: Row( + children: [ + GestureDetector( + onTap: () => context.read().currentPageIndex--, + child: const Icon( + Icons.arrow_back, + ), + ), + const SizedBox( + width: 20, + ), + if (title != null) DidvanText(title!) + ], + ), + ); + } +} diff --git a/lib/pages/splash/splash.dart b/lib/pages/splash/splash.dart index 3b99cfe..da8d1aa 100644 --- a/lib/pages/splash/splash.dart +++ b/lib/pages/splash/splash.dart @@ -1,5 +1,6 @@ import 'package:didvan/config/design_config.dart'; -import 'package:didvan/constants/assets.dart'; +import 'package:didvan/routes/routes.dart'; +import 'package:didvan/widgets/logos/didvan_horizontal_logo.dart'; import 'package:flutter/material.dart'; class Splash extends StatefulWidget { @@ -10,12 +11,23 @@ class Splash extends StatefulWidget { } class _SplashState extends State { + @override + void initState() { + Future.delayed( + const Duration(seconds: 2), + () => Navigator.of(context).pushReplacementNamed( + Routes.authenticaion, + ), + ); + super.initState(); + } + @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(60), color: DesignConfig.lightColorScheme.background, - child: Image.asset(Assets.logoWithTitleAndDesc), + child: const DidvanVerticalLogo(), ); } } diff --git a/lib/routes/route_generator.dart b/lib/routes/route_generator.dart index 0324deb..f55e042 100644 --- a/lib/routes/route_generator.dart +++ b/lib/routes/route_generator.dart @@ -1,3 +1,5 @@ +import 'package:didvan/pages/authentication/authentication.dart'; +import 'package:didvan/pages/authentication/authentication_state.dart'; import 'package:didvan/pages/splash/splash.dart'; import 'package:didvan/pages/splash/splash_state.dart'; import 'package:didvan/routes/routes.dart'; @@ -14,6 +16,13 @@ class RouteGenerator { child: const Splash(), ), ); + case Routes.authenticaion: + return _materialPageRouteGenerator( + ChangeNotifierProvider( + create: (context) => AuthenticationState(), + child: const Authentication(), + ), + ); default: return _errorRoute(); } diff --git a/lib/widgets/didvan/button.dart b/lib/widgets/didvan/button.dart new file mode 100644 index 0000000..ad6dfca --- /dev/null +++ b/lib/widgets/didvan/button.dart @@ -0,0 +1,34 @@ +import 'package:didvan/config/design_config.dart'; +import 'package:didvan/widgets/didvan/text.dart'; +import 'package:flutter/material.dart'; + +class DidvanButton extends StatelessWidget { + final VoidCallback? onPressed; + final String? title; + const DidvanButton({Key? key, this.onPressed, this.title}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SizedBox( + width: double.infinity, + child: MaterialButton( + shape: const RoundedRectangleBorder( + borderRadius: DesignConfig.lowBorderRadius, + ), + height: 48, + color: Theme.of(context).primaryColor, + onPressed: onPressed, + child: _childBuilder(), + ), + ); + } + + Widget? _childBuilder() { + if (title != null) { + return DidvanText( + title!, + color: Colors.white, + ); + } + } +} diff --git a/lib/widgets/didvan/text.dart b/lib/widgets/didvan/text.dart new file mode 100644 index 0000000..cf4811c --- /dev/null +++ b/lib/widgets/didvan/text.dart @@ -0,0 +1,31 @@ +import 'package:didvan/config/design_config.dart'; +import 'package:flutter/material.dart'; + +class DidvanText extends StatelessWidget { + final TextStyle style; + final String text; + final Color? color; + final FontWeight? fontWeight; + final double? fontSize; + + const DidvanText( + this.text, { + Key? key, + this.style = DesignConfig.body1TextStyle, + this.color, + this.fontSize, + this.fontWeight, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Text( + text, + style: style.copyWith( + color: color, + fontWeight: fontWeight, + fontSize: fontSize, + ), + ); + } +} diff --git a/lib/widgets/didvan/text_field.dart b/lib/widgets/didvan/text_field.dart new file mode 100644 index 0000000..bf864fa --- /dev/null +++ b/lib/widgets/didvan/text_field.dart @@ -0,0 +1,106 @@ +import 'package:didvan/config/design_config.dart'; +import 'package:didvan/widgets/didvan/text.dart'; +import 'package:flutter/material.dart'; + +class DidvanTextField extends StatefulWidget { + final void Function(String value)? onChanged; + final bool enabled; + final TextAlign textAlign; + final String? title; + final String? hintText; + final dynamic initialValue; + final String? Function(String? value)? validator; + final TextInputType? textInputType; + const DidvanTextField({ + Key? key, + this.onChanged, + this.enabled = true, + this.title, + this.hintText, + this.initialValue, + this.validator, + this.textInputType, + this.textAlign = TextAlign.right, + }) : super(key: key); + + @override + State createState() => _DidvanTextFieldState(); +} + +class _DidvanTextFieldState extends State { + final FocusNode _focusNode = FocusNode(); + final TextEditingController _controller = TextEditingController(); + + bool _hasError = false; + + @override + void initState() { + _focusNode.addListener(() { + setState(() {}); + }); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (widget.title != null) DidvanText(widget.title!), + if (widget.title != null) const SizedBox(height: 8), + Container( + padding: const EdgeInsets.symmetric(horizontal: 12), + decoration: BoxDecoration( + color: _fillColor(), + borderRadius: DesignConfig.lowBorderRadius, + border: Border.all(color: _borderColor()), + ), + child: TextFormField( + textAlign: widget.textAlign, + keyboardType: widget.textInputType, + focusNode: _focusNode, + controller: _controller, + onChanged: _onChanged, + validator: _validator, + decoration: InputDecoration( + enabled: widget.enabled, + border: InputBorder.none, + hintText: widget.hintText, + hintStyle: Theme.of(context) + .textTheme + .bodyText1! + .copyWith(color: DesignConfig.greyColor5), + ), + ), + ), + ], + ); + } + + Color _borderColor() { + if (_focusNode.hasFocus) { + return Theme.of(context).primaryColor; + } else if (_hasError) { + return Theme.of(context).colorScheme.error; + } + return DesignConfig.greyColor4; + } + + Color _fillColor() { + if (_focusNode.hasFocus) { + return DesignConfig.lightPrimaryColor3; + } else if (_hasError) { + return DesignConfig.lightRedColor; + } + return Theme.of(context).colorScheme.surface; + } + + void _onChanged(String value) { + if (widget.onChanged != null) { + widget.onChanged!(value); + } + } + + String? _validator(String? value) {} +} diff --git a/lib/widgets/logos/didvan_horizontal_logo.dart b/lib/widgets/logos/didvan_horizontal_logo.dart new file mode 100644 index 0000000..19c2aaf --- /dev/null +++ b/lib/widgets/logos/didvan_horizontal_logo.dart @@ -0,0 +1,11 @@ +import 'package:didvan/constants/assets.dart'; +import 'package:flutter/material.dart'; + +class DidvanVerticalLogo extends StatelessWidget { + const DidvanVerticalLogo({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Image.asset(Assets.verticalLogoWithText); + } +} diff --git a/lib/widgets/logos/didvan_vertical_logo.dart b/lib/widgets/logos/didvan_vertical_logo.dart new file mode 100644 index 0000000..e69de29 diff --git a/pubspec.yaml b/pubspec.yaml index e132f26..4eb767f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -62,7 +62,8 @@ flutter: # To add assets to your application, add an assets section, like this: assets: - - lib/assets/logo/logo-t-d.png + - lib/assets/images/logo/logo-v-t.png + - lib/assets/images/logo/logo-h-t.png @@ -77,7 +78,15 @@ flutter: # "family" key with the font family name, and a "fonts" key with a # list giving the asset and other descriptors for the font. For # example: - # fonts: + fonts: + - family: dana-fa + fonts: + - asset: lib/assets/fonts/dana-fa.ttf + + - family: dana + fonts: + - asset: lib/assets/fonts/dana-fa.ttf + # fonts: # - family: Schyler # fonts: # - asset: fonts/Schyler-Regular.ttf