D1APP-32 edit profie (static)

This commit is contained in:
MohammadTaha Basiri 2021-12-16 16:44:17 +03:30
parent 42362c41fa
commit ec321d2e7b
20 changed files with 325 additions and 22 deletions

View File

@ -3,15 +3,17 @@ import 'package:flutter/services.dart';
class DesignConfig { class DesignConfig {
static const backgroundColor = Color(0XFFF8F8FA); static const backgroundColor = Color(0XFFF8F8FA);
static const Color surfaceColor = Colors.white;
static const Color lightPrimaryColor2 = Color(0XFFE6F3FA); static const Color lightPrimaryColor2 = Color(0XFFE6F3FA);
static const Color lightPrimaryColor3 = Color(0XFFF5FAFC); static const Color lightPrimaryColor3 = Color(0XFFF5FAFC);
static const Color primaryColor = Color(0XFF007EA7); static const Color primaryColor = Color(0XFF007EA7);
static const Color darkPrimaryColor2 = Color(0XFF1B3C59); static const Color darkPrimaryColor2 = Color(0XFF1B3C59);
static const Color secontCtaColor = Color(0XFFF5F5F5);
static const Color cardBorderColor = Color(0XFFEBEBEB); static const Color cardBorderColor = Color(0XFFEBEBEB);
static const Color borderColor = Color(0XFFE0E0E0); static const Color borderColor = Color(0XFFE0E0E0);
static const Color hintColor = Color(0XFFE0E0E0); static const Color hintColor = Color(0XFFBBBBBB);
static const Color captionColor = Color(0XFF666666); static const Color captionColor = Color(0XFF666666);
static const Color lightRedColor = Color(0XFFFFF8F8); static const Color lightRedColor = Color(0XFFFFF8F8);
@ -20,22 +22,29 @@ class DesignConfig {
primaryColor: primaryColor, primaryColor: primaryColor,
colorScheme: lightColorScheme, colorScheme: lightColorScheme,
fontFamily: 'Dana-FA', fontFamily: 'Dana-FA',
appBarTheme: const AppBarTheme(
backgroundColor: backgroundColor,
foregroundColor: darkPrimaryColor2,
),
textTheme: const TextTheme( textTheme: const TextTheme(
bodyText1: body1Text, bodyText1: body1Text,
bodyText2: body2Text, bodyText2: body2Text,
caption: captionText, caption: captionText,
subtitle2: subtitle2Text, subtitle2: subtitle2Text,
subtitle1: subtitle1Text, subtitle1: subtitle1Text,
headline3: headline3Text,
), ),
scaffoldBackgroundColor: backgroundColor, scaffoldBackgroundColor: backgroundColor,
); );
static final ThemeData darkTheme = ThemeData();
static const ColorScheme lightColorScheme = ColorScheme( static const ColorScheme lightColorScheme = ColorScheme(
primary: primaryColor, primary: primaryColor,
primaryVariant: Color(0XFF1B3C59), primaryVariant: Color(0XFF1B3C59),
secondary: Color(0XFFD61515), secondary: Color(0XFFD61515),
secondaryVariant: Color(0XFFA30001), secondaryVariant: Color(0XFFA30001),
surface: Colors.white, surface: surfaceColor,
background: backgroundColor, background: backgroundColor,
error: Color(0XFFF00505), error: Color(0XFFF00505),
onPrimary: Colors.white, onPrimary: Colors.white,
@ -48,6 +57,10 @@ class DesignConfig {
static const ColorScheme currentColorScheme = lightColorScheme; static const ColorScheme currentColorScheme = lightColorScheme;
static const TextStyle headline3Text = TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
);
static const TextStyle subtitle1Text = TextStyle( static const TextStyle subtitle1Text = TextStyle(
fontSize: 17, fontSize: 17,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,

View File

@ -22,6 +22,8 @@ class Didvan extends StatelessWidget {
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
title: 'Didvan', title: 'Didvan',
theme: DesignConfig.lightTheme, theme: DesignConfig.lightTheme,
darkTheme: DesignConfig.darkTheme,
themeMode: ThemeMode.light,
onGenerateRoute: (settings) => RouteGenerator.generateRoute(settings), onGenerateRoute: (settings) => RouteGenerator.generateRoute(settings),
initialRoute: '/', initialRoute: '/',
localizationsDelegates: const [ localizationsDelegates: const [

View File

@ -0,0 +1,7 @@
class AppBarData {
final String? title;
final String? subtitle;
final bool hasBack;
AppBarData({this.title, this.subtitle, this.hasBack = false});
}

View File

@ -30,7 +30,7 @@ class PasswordInput extends StatelessWidget {
child: DidvanText( child: DidvanText(
'فراموشی رمز عبور', 'فراموشی رمز عبور',
style: Theme.of(context).textTheme.subtitle2, style: Theme.of(context).textTheme.subtitle2,
color: Theme.of(context).primaryColor, color: Theme.of(context).colorScheme.primary,
), ),
), ),
const Spacer(), const Spacer(),

View File

@ -48,7 +48,7 @@ class PhoneNumberInput extends StatelessWidget {
style: Theme.of(context) style: Theme.of(context)
.textTheme .textTheme
.caption! .caption!
.copyWith(color: Theme.of(context).primaryColor), .copyWith(color: Theme.of(context).colorScheme.primary),
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = () { ..onTap = () {
//TODO: Needs implementaion //TODO: Needs implementaion
@ -60,7 +60,7 @@ class PhoneNumberInput extends StatelessWidget {
style: Theme.of(context) style: Theme.of(context)
.textTheme .textTheme
.caption! .caption!
.copyWith(color: Theme.of(context).primaryColor), .copyWith(color: Theme.of(context).colorScheme.primary),
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = () { ..onTap = () {
//TODO: Needs implementaion //TODO: Needs implementaion

View File

@ -48,8 +48,8 @@ class Verification extends StatelessWidget {
fieldHeight: 48, fieldHeight: 48,
fieldWidth: 48, fieldWidth: 48,
inactiveColor: DesignConfig.borderColor, inactiveColor: DesignConfig.borderColor,
activeFillColor: Theme.of(context).primaryColorLight, activeFillColor: Theme.of(context).colorScheme.primary,
activeColor: Theme.of(context).primaryColor, activeColor: Theme.of(context).colorScheme.primary,
borderRadius: DesignConfig.lowBorderRadius, borderRadius: DesignConfig.lowBorderRadius,
borderWidth: 1, borderWidth: 1,
shape: PinCodeFieldShape.box, shape: PinCodeFieldShape.box,

View File

@ -1,3 +1,11 @@
import 'package:didvan/models/view/app_bar_data.dart';
import 'package:didvan/pages/home/profile/edit_profile/widgets/profile_photo.dart';
import 'package:didvan/pages/home/profile/edit_profile/widgets/switch.dart';
import 'package:didvan/pages/home/profile/widgets/menu_item.dart';
import 'package:didvan/widgets/didvan/card.dart';
import 'package:didvan/widgets/didvan/divider.dart';
import 'package:didvan/widgets/didvan/scaffold.dart';
import 'package:didvan/widgets/didvan/text_field.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class EditProfile extends StatelessWidget { class EditProfile extends StatelessWidget {
@ -5,6 +13,58 @@ class EditProfile extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return const Scaffold(); return DidvanScaffold(
appBarData: AppBarData(),
slivers: [
const SliverToBoxAdapter(
child: ProfilePhoto(),
),
SliverPadding(
padding: const EdgeInsets.all(16),
sliver: SliverToBoxAdapter(
child: DidvanCard(
child: Column(
children: [
DidvanTextField(
title: 'نام کاربری',
hintText: 'انتخاب نام کاربری (اختیاری)',
onChanged: (value) {
//TODO: Needs implementation
},
),
const SizedBox(height: 16),
DidvanTextField(
title: 'ایمیل',
hintText: 'مثال: example@email.com',
onChanged: (value) {
//TODO: Meeds implementaion
},
),
const SizedBox(height: 16),
const DidvanTextField(
title: 'موبایل',
enabled: false,
hintText: '09123456789', //TODO: Needs api
),
const SizedBox(height: 16),
DidvanSwitch(
value: true, //TODO: Needs api
title: 'ورود با اثر انگشت',
onChanged: (value) => {
//TODO: Needs implementaion
},
),
const DidvanDivider(),
MenuItem(
title: 'تغییر رمز عبور',
onTap: () {},
),
],
),
),
),
),
],
);
} }
} }

View File

@ -0,0 +1,42 @@
import 'package:didvan/config/design_config.dart';
import 'package:didvan/constants/app_icons.dart';
import 'package:flutter/material.dart';
class ProfilePhoto extends StatelessWidget {
const ProfilePhoto({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
//TODO: Needs implementation
},
child: Center(
child: Stack(
children: [
Container(
height: 96,
width: 96,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: DesignConfig.lightPrimaryColor2,
),
child: const Icon(
DidvanIcons.profile_solid,
size: 60,
color: DesignConfig.darkPrimaryColor2,
),
),
const Positioned(
bottom: 4,
right: 4,
child: Icon(
DidvanIcons.camera_regular,
),
),
],
),
),
);
}
}

View File

@ -0,0 +1,50 @@
import 'package:didvan/config/design_config.dart';
import 'package:didvan/pages/home/profile/widgets/menu_item.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class DidvanSwitch extends StatefulWidget {
final bool value;
final String title;
final IconData? icon;
final void Function(bool value) onChanged;
const DidvanSwitch({
Key? key,
required this.value,
required this.title,
this.icon,
required this.onChanged,
}) : super(key: key);
@override
_DidvanSwitchState createState() => _DidvanSwitchState();
}
class _DidvanSwitchState extends State<DidvanSwitch> {
bool _value = false;
@override
void initState() {
_value = widget.value;
super.initState();
}
@override
Widget build(BuildContext context) {
return MenuItem(
title: widget.title,
onTap: () => widget.onChanged(_value),
icon: widget.icon,
trailing: CupertinoSwitch(
activeColor: Theme.of(context).colorScheme.primary,
value: _value,
onChanged: (value) {
setState(() {
_value = value;
});
widget.onChanged(value);
},
),
);
}
}

View File

@ -33,7 +33,8 @@ class Profile extends StatelessWidget {
MenuItem( MenuItem(
title: 'ویرایش پروفایل', title: 'ویرایش پروفایل',
icon: DidvanIcons.user_edit_regular, icon: DidvanIcons.user_edit_regular,
onTap: () => {}, onTap: () =>
Navigator.of(context).pushNamed(Routes.editProfile),
), ),
const DidvanDivider(), const DidvanDivider(),
MenuItem( MenuItem(
@ -88,7 +89,7 @@ class Profile extends StatelessWidget {
const SizedBox(height: 16), const SizedBox(height: 16),
DidvanText( DidvanText(
'نسخه نرم‌افزار: آزمایشی', 'نسخه نرم‌افزار: آزمایشی',
style: Theme.of(context).textTheme.bodyText2, style: Theme.of(context).textTheme.caption,
), ),
], ],
), ),

View File

@ -8,6 +8,7 @@ class MenuItem extends StatelessWidget {
final IconData? icon; final IconData? icon;
final String? suffix; final String? suffix;
final VoidCallback onTap; final VoidCallback onTap;
final Widget? trailing;
final Color color; final Color color;
const MenuItem({ const MenuItem({
Key? key, Key? key,
@ -16,6 +17,7 @@ class MenuItem extends StatelessWidget {
this.suffix, this.suffix,
required this.onTap, required this.onTap,
this.color = DesignConfig.darkPrimaryColor2, this.color = DesignConfig.darkPrimaryColor2,
this.trailing,
}) : super(key: key); }) : super(key: key);
@override @override
@ -28,6 +30,7 @@ class MenuItem extends StatelessWidget {
if (icon != null) const SizedBox(width: 4), if (icon != null) const SizedBox(width: 4),
DidvanText(title, color: color), DidvanText(title, color: color),
const Spacer(), const Spacer(),
trailing ??
Icon( Icon(
DidvanIcons.angle_left_regular, DidvanIcons.angle_left_regular,
size: 18, size: 18,

View File

@ -40,7 +40,7 @@ class _SearchFieldState extends State<SearchField> {
Radius.circular(4), Radius.circular(4),
), ),
borderSide: BorderSide( borderSide: BorderSide(
color: Theme.of(context).primaryColor, color: Theme.of(context).colorScheme.primary,
), ),
), ),
prefixIcon: const Icon( prefixIcon: const Icon(

View File

@ -0,0 +1,13 @@
import 'package:didvan/providers/core_provider.dart';
import 'package:flutter/material.dart';
class SettingsProvider extends CoreProvier {
ThemeMode _themeMode = ThemeMode.light;
set themeMode(ThemeMode themeMode) {
_themeMode = themeMode;
notifyListeners();
}
ThemeMode get themeMode => _themeMode;
}

View File

@ -3,6 +3,7 @@ import 'package:didvan/pages/authentication/authentication.dart';
import 'package:didvan/pages/authentication/authentication_state.dart'; import 'package:didvan/pages/authentication/authentication_state.dart';
import 'package:didvan/pages/home/home.dart'; import 'package:didvan/pages/home/home.dart';
import 'package:didvan/pages/home/home_state.dart'; import 'package:didvan/pages/home/home_state.dart';
import 'package:didvan/pages/home/profile/edit_profile/edit_profile.dart';
import 'package:didvan/pages/splash/splash.dart'; import 'package:didvan/pages/splash/splash.dart';
import 'package:didvan/pages/splash/splash_state.dart'; import 'package:didvan/pages/splash/splash_state.dart';
import 'package:didvan/routes/routes.dart'; import 'package:didvan/routes/routes.dart';
@ -33,6 +34,10 @@ class RouteGenerator {
child: const Home(), child: const Home(),
), ),
); );
case Routes.editProfile:
return _createRoute(
const EditProfile(),
);
default: default:
return _errorRoute(); return _errorRoute();
} }

View File

@ -3,4 +3,5 @@ class Routes {
static const String home = '/home'; static const String home = '/home';
static const String authenticaion = '/authentication'; static const String authenticaion = '/authentication';
static const String profile = '/profile'; static const String profile = '/profile';
static const String editProfile = '/edit-profile';
} }

View File

@ -0,0 +1,40 @@
import 'package:didvan/config/design_config.dart';
import 'package:didvan/models/view/app_bar_data.dart';
import 'package:didvan/widgets/didvan/text.dart';
import 'package:flutter/material.dart';
class DidvanAppBar extends StatelessWidget {
final AppBarData appBarData;
const DidvanAppBar({Key? key, required this.appBarData}) : super(key: key);
@override
Widget build(BuildContext context) {
final MediaQueryData d = MediaQuery.of(context);
return AnimatedContainer(
duration: DesignConfig.lowAnimationDuration,
child: Padding(
padding: EdgeInsets.only(top: d.padding.top, right: 4, left: 20),
child: Row(
children: [
IconButton(
onPressed: () => Navigator.of(context).pop(),
color: DesignConfig.darkPrimaryColor2,
icon: const Icon(Icons.arrow_back),
),
const SizedBox(width: 16),
Column(
children: [
if (appBarData.title != null)
DidvanText(
appBarData.title!,
style: Theme.of(context).textTheme.headline3,
color: DesignConfig.darkPrimaryColor2,
),
],
),
],
),
),
);
}
}

View File

@ -16,7 +16,7 @@ class DidvanButton extends StatelessWidget {
borderRadius: DesignConfig.lowBorderRadius, borderRadius: DesignConfig.lowBorderRadius,
), ),
height: 48, height: 48,
color: Theme.of(context).primaryColor, color: Theme.of(context).colorScheme.primary,
onPressed: onPressed, onPressed: onPressed,
child: _childBuilder(), child: _childBuilder(),
), ),

View File

@ -9,7 +9,7 @@ class DidvanDivider extends StatelessWidget {
return Container( return Container(
height: 1, height: 1,
width: double.infinity, width: double.infinity,
margin: const EdgeInsets.symmetric(vertical: 12), margin: const EdgeInsets.symmetric(vertical: 16),
color: DesignConfig.borderColor, color: DesignConfig.borderColor,
); );
} }

View File

@ -0,0 +1,58 @@
import 'package:didvan/models/view/app_bar_data.dart';
import 'package:didvan/widgets/didvan/app_bar.dart';
import 'package:flutter/material.dart';
class DidvanScaffold extends StatefulWidget {
final List<Widget>? slivers;
final AppBarData appBarData;
final bool hasPadding;
const DidvanScaffold({
Key? key,
this.slivers,
required this.appBarData,
this.hasPadding = true,
}) : super(key: key);
@override
State<DidvanScaffold> createState() => _DidvanScaffoldState();
}
class _DidvanScaffoldState extends State<DidvanScaffold> {
bool _isElevated = false;
final ScrollController _scrollController = ScrollController();
@override
void initState() {
_scrollController.addListener(() => _handleAppBarElevation());
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar(
automaticallyImplyLeading: false,
pinned: true,
flexibleSpace: DidvanAppBar(appBarData: widget.appBarData),
),
if (widget.slivers != null) ...widget.slivers!
],
),
);
}
void _handleAppBarElevation() {
if (_scrollController.position.pixels > kToolbarHeight && !_isElevated) {
setState(() {
_isElevated = true;
});
}
if (_scrollController.position.pixels < kToolbarHeight && _isElevated) {
setState(() {
_isElevated = false;
});
}
}
}

View File

@ -53,7 +53,11 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (widget.title != null) DidvanText(widget.title!), if (widget.title != null)
DidvanText(
widget.title!,
color: !widget.enabled ? DesignConfig.hintColor : null,
),
if (widget.title != null) const SizedBox(height: 8), if (widget.title != null) const SizedBox(height: 8),
Container( Container(
padding: const EdgeInsets.symmetric(horizontal: 12).copyWith( padding: const EdgeInsets.symmetric(horizontal: 12).copyWith(
@ -82,7 +86,7 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
hintText: widget.hintText, hintText: widget.hintText,
hintStyle: Theme.of(context) hintStyle: Theme.of(context)
.textTheme .textTheme
.bodyText1! .bodyText2!
.copyWith(color: DesignConfig.hintColor), .copyWith(color: DesignConfig.hintColor),
), ),
), ),
@ -93,7 +97,7 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
Color _borderColor() { Color _borderColor() {
if (_focusNode.hasFocus) { if (_focusNode.hasFocus) {
return Theme.of(context).primaryColor; return Theme.of(context).colorScheme.primary;
} else if (_hasError) { } else if (_hasError) {
return Theme.of(context).colorScheme.error; return Theme.of(context).colorScheme.error;
} }
@ -101,9 +105,13 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
} }
Color _fillColor() { Color _fillColor() {
if (!widget.enabled) {
return DesignConfig.secontCtaColor;
}
if (_focusNode.hasFocus) { if (_focusNode.hasFocus) {
return DesignConfig.lightPrimaryColor3; return DesignConfig.lightPrimaryColor3;
} else if (_hasError) { }
if (_hasError) {
return DesignConfig.lightRedColor; return DesignConfig.lightRedColor;
} }
return Theme.of(context).colorScheme.surface; return Theme.of(context).colorScheme.surface;