D1APP-110 font size and style customizations added

This commit is contained in:
MohammadTaha Basiri 2022-03-08 22:09:46 +03:30
parent 5363f327e0
commit 7abc378a14
24 changed files with 299 additions and 139 deletions

2
.gitignore vendored
View File

@ -44,5 +44,3 @@ app.*.map.json
/android/app/debug
/android/app/profile
/android/app/release
.fandogh/

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,10 +1,12 @@
import 'package:didvan/config/theme_data.dart';
import 'package:didvan/main.dart';
import 'package:didvan/providers/theme_provider.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
class DesignConfig {
static BuildContext get context => navigatorKey.currentContext!;
static BuildContext? get context => navigatorKey.currentContext;
static const BorderRadius lowBorderRadius = BorderRadius.all(
Radius.circular(8),
@ -17,7 +19,7 @@ class DesignConfig {
);
static Border get cardBorder => Border.all(
color: Theme.of(context).colorScheme.cardBorder,
color: Theme.of(context!).colorScheme.cardBorder,
width: 0.5,
);
@ -29,7 +31,10 @@ class DesignConfig {
)
];
static Brightness get brightness => Theme.of(context).brightness;
static String get fontFamily => context!.read<ThemeProvider>().fontFamily;
static double get fontScale => context!.read<ThemeProvider>().fontScale;
static Brightness get brightness => Theme.of(context!).brightness;
static bool get isDark => brightness == Brightness.dark;
static const Duration lowAnimationDuration = Duration(milliseconds: 300);
@ -39,8 +44,8 @@ class DesignConfig {
statusBarIconBrightness:
brightness == Brightness.dark ? Brightness.light : Brightness.dark,
statusBarColor:
Theme.of(context).colorScheme.background.withOpacity(0.5),
systemNavigationBarColor: Theme.of(context).colorScheme.surface,
Theme.of(context!).colorScheme.background.withOpacity(0.5),
systemNavigationBarColor: Theme.of(context!).colorScheme.surface,
systemNavigationBarDividerColor: Colors.transparent,
systemNavigationBarIconBrightness:
brightness == Brightness.dark ? Brightness.light : Brightness.dark,

View File

@ -1,3 +1,4 @@
import 'package:didvan/config/design_config.dart';
import 'package:flutter/material.dart';
class LightThemeConfig {
@ -6,12 +7,11 @@ class LightThemeConfig {
static const Color _black = Color(0xFF292929);
static const Color _background = Color(0xFFF8F8FA);
static final ThemeData themeData = ThemeData(
static ThemeData get themeData => ThemeData(
backgroundColor: _background,
scaffoldBackgroundColor: _background,
colorScheme: _colorScheme,
fontFamily: 'Dana-FA',
textTheme: _textTheme,
textTheme: _TextThemeData.data,
cardColor: _colorScheme.surface,
checkboxTheme: CheckboxThemeData(
fillColor: MaterialStateProperty.all<Color>(_colorScheme.primary),
@ -24,16 +24,6 @@ class LightThemeConfig {
),
);
static final TextTheme _textTheme = const TextTheme(
bodyText1: _body1Text,
bodyText2: _body2Text,
caption: _captionText,
subtitle2: _subtitle2Text,
subtitle1: _subtitle1Text,
headline3: _headline3Text,
overline: _overlineText,
).apply(bodyColor: _black, displayColor: _black);
static const ColorScheme _colorScheme = ColorScheme(
primary: _primary,
primaryContainer: _white,
@ -49,35 +39,6 @@ class LightThemeConfig {
onError: _white,
brightness: Brightness.light,
);
static const TextStyle _headline3Text = TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
);
static const TextStyle _subtitle1Text = TextStyle(
fontSize: 17,
fontWeight: FontWeight.w700,
);
static const TextStyle _subtitle2Text = TextStyle(
fontSize: 15,
fontWeight: FontWeight.w700,
);
static const TextStyle _body1Text = TextStyle(
fontSize: 15,
fontWeight: FontWeight.w700,
);
static const TextStyle _body2Text = TextStyle(
fontSize: 15,
fontWeight: FontWeight.w400,
);
static const TextStyle _captionText = TextStyle(
fontSize: 13,
fontWeight: FontWeight.w400,
);
static const TextStyle _overlineText = TextStyle(
fontSize: 12,
fontWeight: FontWeight.w300,
);
}
class DarkThemeConfig {
@ -85,12 +46,11 @@ class DarkThemeConfig {
static const Color _white = Color(0xFFFFFFFF);
static const Color _background = Color(0xFF202224);
static final ThemeData themeData = ThemeData(
static ThemeData get themeData => ThemeData(
backgroundColor: _background,
scaffoldBackgroundColor: _background,
colorScheme: _colorScheme,
fontFamily: 'Dana-FA',
textTheme: _textTheme,
textTheme: _TextThemeData.data,
iconTheme: IconThemeData(
color: _colorScheme.text,
),
@ -104,16 +64,6 @@ class DarkThemeConfig {
cardColor: _colorScheme.surface,
);
static final TextTheme _textTheme = const TextTheme(
bodyText1: _body1Text,
bodyText2: _body2Text,
caption: _captionText,
subtitle2: _subtitle2Text,
subtitle1: _subtitle1Text,
headline3: _headline3Text,
overline: _overlineText,
).apply(bodyColor: text, displayColor: text);
static const ColorScheme _colorScheme = ColorScheme(
primary: _primary,
primaryContainer: _white,
@ -130,35 +80,6 @@ class DarkThemeConfig {
brightness: Brightness.dark,
);
static const TextStyle _headline3Text = TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
);
static const TextStyle _subtitle1Text = TextStyle(
fontSize: 17,
fontWeight: FontWeight.w700,
);
static const TextStyle _subtitle2Text = TextStyle(
fontSize: 15,
fontWeight: FontWeight.w700,
);
static const TextStyle _body1Text = TextStyle(
fontSize: 15,
fontWeight: FontWeight.w700,
);
static const TextStyle _body2Text = TextStyle(
fontSize: 15,
fontWeight: FontWeight.w400,
);
static const TextStyle _captionText = TextStyle(
fontSize: 13,
fontWeight: FontWeight.w400,
);
static const TextStyle _overlineText = TextStyle(
fontSize: 12,
fontWeight: FontWeight.w300,
);
// Grey colors
static const Color white = Color(0xFFFFFFFF);
static const Color title = Color(0xFFF5F5F5);
@ -173,6 +94,49 @@ class DarkThemeConfig {
static const Color success = Color(0xFF32A64C);
}
class _TextThemeData {
static TextTheme get data => DesignConfig.context == null
? const TextTheme()
: TextTheme(
bodyText1: _body1Text,
bodyText2: _body2Text,
caption: _captionText,
subtitle2: _subtitle2Text,
subtitle1: _subtitle1Text,
headline3: _headline3Text,
overline: _overlineText,
);
static TextStyle get _headline3Text => TextStyle(
fontSize: 20 * DesignConfig.fontScale,
fontWeight: FontWeight.w600,
);
static TextStyle get _subtitle1Text => TextStyle(
fontSize: 17 * DesignConfig.fontScale,
fontWeight: FontWeight.w700,
);
static TextStyle get _subtitle2Text => TextStyle(
fontSize: 15 * DesignConfig.fontScale,
fontWeight: FontWeight.w700,
);
static TextStyle get _body1Text => TextStyle(
fontSize: 15 * DesignConfig.fontScale,
fontWeight: FontWeight.w700,
);
static TextStyle get _body2Text => TextStyle(
fontSize: 15 * DesignConfig.fontScale,
fontWeight: FontWeight.w400,
);
static TextStyle get _captionText => TextStyle(
fontSize: 13 * DesignConfig.fontScale,
fontWeight: FontWeight.w400,
);
static TextStyle get _overlineText => TextStyle(
fontSize: 12 * DesignConfig.fontScale,
fontWeight: FontWeight.w300,
);
}
extension DidvanColorScheme on ColorScheme {
// Secondary colors
Color get secondaryDisabled => brightness == Brightness.dark

View File

@ -33,8 +33,14 @@ class Didvan extends StatelessWidget {
navigatorKey: navigatorKey,
debugShowCheckedModeBanner: false,
title: 'Didvan',
theme: LightThemeConfig.themeData,
darkTheme: DarkThemeConfig.themeData,
theme: LightThemeConfig.themeData.copyWith(
textTheme: LightThemeConfig.themeData.textTheme.apply(
fontFamily: themeProvider.fontFamily,
)),
darkTheme: DarkThemeConfig.themeData.copyWith(
textTheme: DarkThemeConfig.themeData.textTheme.apply(
fontFamily: themeProvider.fontFamily,
)),
color: LightThemeConfig.themeData.primaryColor,
themeMode: themeProvider.themeMode,
onGenerateRoute: (settings) => RouteGenerator.generateRoute(settings),

View File

@ -0,0 +1,13 @@
import 'package:flutter/material.dart';
class SettingsData {
final String fontFamily;
final double fontScale;
final ThemeMode themeMode;
SettingsData({
required this.fontFamily,
required this.fontScale,
required this.themeMode,
});
}

View File

@ -3,6 +3,8 @@ import 'package:flutter/material.dart';
class ThemeProvider extends CoreProvier {
ThemeMode _themeMode = ThemeMode.system;
String _fontFamily = 'Dana-FA';
double _fontScale = 1;
set themeMode(ThemeMode value) {
_themeMode = value;
@ -10,4 +12,18 @@ class ThemeProvider extends CoreProvier {
}
ThemeMode get themeMode => _themeMode;
set fontFamily(String value) {
_fontFamily = value;
notifyListeners();
}
String get fontFamily => _fontFamily;
set fontScale(double value) {
_fontScale = value;
notifyListeners();
}
double get fontScale => _fontScale;
}

View File

@ -1,3 +1,4 @@
import 'package:didvan/models/settings_data.dart';
import 'package:didvan/services/media/media.dart';
import 'package:didvan/services/storage/storage.dart';
import 'package:firebase_core/firebase_core.dart';
@ -17,10 +18,19 @@ class AppInitializer {
}
}
static Future<ThemeMode> initilizeSettings() async {
static Future<SettingsData> initilizeSettings() async {
final brightness = await StorageService.getValue(key: 'brightness');
if (brightness != null) {
return brightness == 'dark' ? ThemeMode.dark : ThemeMode.light;
final themeMode = brightness == 'dark' ? ThemeMode.dark : ThemeMode.light;
final fontFamily = await StorageService.getValue(key: 'fontFamily');
final fontScale = double.parse(
await StorageService.getValue(key: 'fontSizeScale'),
);
return SettingsData(
fontFamily: fontFamily,
fontScale: fontScale,
themeMode: themeMode,
);
} else {
await StorageService.setValue(
key: 'notificationTimeRangeStart',
@ -42,7 +52,11 @@ class AppInitializer {
key: 'brightness',
value: 'light',
);
return ThemeMode.light;
return SettingsData(
fontFamily: 'Dana-FA',
fontScale: 1,
themeMode: ThemeMode.light,
);
}
}

View File

@ -1,11 +1,13 @@
import 'package:didvan/models/requests/news.dart';
import 'package:didvan/models/requests/radar.dart';
import 'package:didvan/models/requests/studio.dart';
class RequestHelper {
static const String baseUrl = 'https://api.didvan.app';
static const String _baseUserUrl = baseUrl + '/user';
static const String _baseRadarUrl = baseUrl + '/radar';
static const String _baseNewsUrl = baseUrl + '/news';
static const String _baseStudioUrl = baseUrl + '/studio';
static const String _baseDirectUrl = _baseUserUrl + '/direct';
static const String confirmUsername = _baseUserUrl + '/confirmUsername';
@ -86,6 +88,30 @@ class RequestHelper {
MapEntry('search', args.search),
]);
static String markStudioItem(int id) => _baseStudioUrl + '/$id/mark';
static String studioItemComments(int id) => _baseStudioUrl + '/$id/comments';
static String addStudioItemComment(int id) =>
_baseStudioUrl + '/$id/comments/add';
static String feedbackStudioItemComment(int radarId, int id) =>
_baseStudioUrl + '/$radarId/comments/$id/feedback';
static String studioItemDetails(int id, StudioRequestArgs args) =>
_baseStudioUrl +
'/$id' +
_urlConcatGenerator([
MapEntry('page', args.page.toString()),
MapEntry('search', args.search),
MapEntry('order', args.order),
MapEntry('type', args.type),
]);
static String studioItemOverviews({required StudioRequestArgs args}) =>
_baseStudioUrl +
_urlConcatGenerator([
MapEntry('page', args.page.toString()),
MapEntry('search', args.search),
MapEntry('order', args.order),
MapEntry('type', args.type),
]);
static String _urlConcatGenerator(List<MapEntry<String, String?>> additions) {
String result = '';
additions.removeWhere((element) => element.value == null);

View File

@ -10,7 +10,7 @@ class StorageService {
required String key,
required dynamic value,
}) async {
await _storage.write(key: key, value: value);
await _storage.write(key: key, value: value.toString());
}
static Future getValue({required String key}) async {

View File

@ -43,7 +43,7 @@ class DateTimeUtils {
);
final Jalali? result = await showPersianDatePicker(
context: DesignConfig.context,
context: DesignConfig.context!,
initialDate: initialJalali,
firstDate: firstDate,
lastDate: lastDate,

View File

@ -65,7 +65,7 @@ class CommentsState extends CoreProvier {
}
Future<void> addComment() async {
final user = DesignConfig.context.read<UserProvider>().user;
final user = DesignConfig.context!.read<UserProvider>().user;
if (replyingTo != null) {
comments.firstWhere((comment) => comment.id == commentId).replies.add(
Reply(

View File

@ -12,6 +12,7 @@ import 'package:didvan/views/home/settings/general_settings/settings_state.dart'
import 'package:didvan/views/home/widgets/menu_item.dart';
import 'package:didvan/views/widgets/didvan/card.dart';
import 'package:didvan/views/widgets/didvan/divider.dart';
import 'package:didvan/views/widgets/didvan/radial_button.dart';
import 'package:didvan/views/widgets/didvan/scaffold.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:didvan/views/widgets/item_title.dart';
@ -20,9 +21,21 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:provider/provider.dart';
class GeneralSettings extends StatelessWidget {
class GeneralSettings extends StatefulWidget {
const GeneralSettings({Key? key}) : super(key: key);
@override
State<GeneralSettings> createState() => _GeneralSettingsState();
}
class _GeneralSettingsState extends State<GeneralSettings> {
String get _fontScaleSuffix {
final fontScale = DesignConfig.fontScale;
if (fontScale == 1) return 'متوسط';
if (fontScale == 1.15) return 'بزرگ';
return 'کوچک';
}
@override
Widget build(BuildContext context) {
return Consumer<GeneralSettingsState>(
@ -48,15 +61,17 @@ class GeneralSettings extends StatelessWidget {
child: Column(
children: [
MenuItem(
suffix: 'نیاز به پیاده‌سازی',
suffix: DesignConfig.fontFamily == 'Dana-FA'
? 'دانا'
: 'ایران سنس',
title: 'فونت برنامه',
onTap: () {},
onTap: _showFontFamilyBottomSheet,
),
const DidvanDivider(),
MenuItem(
suffix: 'نیاز به پیاده‌سازی',
suffix: _fontScaleSuffix,
title: 'اندازه متن',
onTap: () {},
onTap: _showFontScaleBottomSheet,
),
],
),
@ -80,6 +95,87 @@ class GeneralSettings extends StatelessWidget {
);
}
void _showFontFamilyBottomSheet() {
final themeProvider = context.read<ThemeProvider>();
final state = context.read<GeneralSettingsState>();
ActionSheetUtils.showBottomSheet(
data: ActionSheetData(
content: StatefulBuilder(
builder: (context, setState) => Column(
children: [
DidvanRadialButton(
title: 'دانا',
fontFamily: 'Dana-FA',
onSelected: () {
state.fontFamily = 'Dana-FA';
setState(() {});
},
value: state.fontFamily == 'Dana-FA',
),
const SizedBox(height: 24),
DidvanRadialButton(
title: 'ایران سنس',
fontFamily: 'Iransans-FA',
onSelected: () {
state.fontFamily = 'Iransans-FA';
setState(() {});
},
value: state.fontFamily == 'Iransans-FA',
),
],
),
),
title: 'انتخاب فونت برنامه',
titleIcon: DidvanIcons.font_regular,
onConfirmed: () => themeProvider.fontFamily = state.fontFamily,
),
);
}
void _showFontScaleBottomSheet() {
final themeProvider = context.read<ThemeProvider>();
final state = context.read<GeneralSettingsState>();
ActionSheetUtils.showBottomSheet(
data: ActionSheetData(
content: StatefulBuilder(
builder: (context, setState) => Column(
children: [
DidvanRadialButton(
title: 'بزرگ',
onSelected: () {
state.fontSizeScale = 1.15;
setState(() {});
},
value: state.fontSizeScale == 1.15,
),
const SizedBox(height: 24),
DidvanRadialButton(
title: 'متوسط',
onSelected: () {
state.fontSizeScale = 1;
setState(() {});
},
value: state.fontSizeScale == 1,
),
const SizedBox(height: 24),
DidvanRadialButton(
title: 'کوچک',
onSelected: () {
state.fontSizeScale = 0.85;
setState(() {});
},
value: state.fontSizeScale == 0.85,
),
],
),
),
title: 'انتخاب اندازه متن',
titleIcon: DidvanIcons.font_regular,
onConfirmed: () => themeProvider.fontScale = state.fontSizeScale,
),
);
}
Future<void> _pickTimeRange(BuildContext context) async {
ActionSheetUtils.showBottomSheet(
data: ActionSheetData(

View File

@ -94,8 +94,11 @@ class _SplashState extends State<Splash> {
});
}
await AppInitializer.setupServices();
final ThemeMode themeMode = await AppInitializer.initilizeSettings();
context.read<ThemeProvider>().themeMode = themeMode;
final settingsData = await AppInitializer.initilizeSettings();
final themeProvider = context.read<ThemeProvider>();
themeProvider.themeMode = settingsData.themeMode;
themeProvider.fontFamily = settingsData.fontFamily;
themeProvider.fontScale = settingsData.fontScale;
await Future.delayed(
const Duration(milliseconds: 200),
() => setState(() {

View File

@ -6,11 +6,13 @@ class DidvanRadialButton extends StatelessWidget {
final String title;
final VoidCallback onSelected;
final bool value;
final String? fontFamily;
const DidvanRadialButton({
Key? key,
required this.title,
required this.onSelected,
required this.value,
this.fontFamily,
}) : super(key: key);
@override
@ -45,7 +47,12 @@ class DidvanRadialButton extends StatelessWidget {
),
),
const SizedBox(width: 8),
DidvanText(title),
DidvanText(
title,
style: Theme.of(context).textTheme.bodyText2!.copyWith(
fontFamily: fontFamily,
),
),
],
),
),

View File

@ -1,3 +1,4 @@
import 'package:didvan/config/design_config.dart';
import 'package:flutter/material.dart';
class DidvanText extends StatelessWidget {
@ -32,7 +33,7 @@ class DidvanText extends StatelessWidget {
color: color,
fontWeight: fontWeight,
fontSize: fontSize,
)).copyWith(fontFamily: isEnglishFont ? 'Dana' : null),
)).copyWith(fontFamily: isEnglishFont ? DesignConfig.fontFamily : null),
overflow: overflow,
textAlign: textAlign,
maxLines: maxLines,

View File

@ -99,7 +99,7 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
style: Theme.of(context)
.textTheme
.bodyText2!
.copyWith(fontFamily: 'Dana'),
.copyWith(fontFamily: DesignConfig.fontFamily.padRight(3)),
decoration: InputDecoration(
suffixIcon: _suffixBuilder(),
enabled: widget.enabled,

View File

@ -151,10 +151,21 @@ flutter:
- asset: lib/assets/fonts/Dana-FaNum-Regular.ttf
- asset: lib/assets/fonts/Dana-FaNum-Thin.ttf
- asset: lib/assets/fonts/Dana-FaNum-UltraBold.ttf
- family: Iransans-FA
fonts:
- asset: lib/assets/fonts/IRANSansMobile-FaNum-Black.ttf
- asset: lib/assets/fonts/IRANSansMobile-FaNum-Bold.ttf
- asset: lib/assets/fonts/IRANSansMobile-FaNum-Light.ttf
- asset: lib/assets/fonts/IRANSansMobile-FaNum-Medium.ttf
- asset: lib/assets/fonts/IRANSansMobile-FaNum-UltraLight.ttf
- asset: lib/assets/fonts/IRANSansMobile-FaNum.ttf
- family: Dana
fonts:
- asset: lib/assets/fonts/Dana.ttf
- family: Iransans
fonts:
- asset: lib/assets/fonts/IRANSansMobile.ttf
- family: Dicon
fonts:
- asset: lib/assets/icons/Dicon.ttf