diff --git a/lib/assets/fonts/IRANYEKANBLACK.TTF b/lib/assets/fonts/IRANYEKANBLACK.TTF new file mode 100644 index 0000000..610d355 Binary files /dev/null and b/lib/assets/fonts/IRANYEKANBLACK.TTF differ diff --git a/lib/assets/fonts/IRANYEKANBOLD.TTF b/lib/assets/fonts/IRANYEKANBOLD.TTF new file mode 100644 index 0000000..a8552e1 Binary files /dev/null and b/lib/assets/fonts/IRANYEKANBOLD.TTF differ diff --git a/lib/assets/fonts/IRANYEKANEXTRABLACK.TTF b/lib/assets/fonts/IRANYEKANEXTRABLACK.TTF new file mode 100644 index 0000000..7860217 Binary files /dev/null and b/lib/assets/fonts/IRANYEKANEXTRABLACK.TTF differ diff --git a/lib/assets/fonts/IRANYEKANEXTRABOLD.TTF b/lib/assets/fonts/IRANYEKANEXTRABOLD.TTF new file mode 100644 index 0000000..9d83f0d Binary files /dev/null and b/lib/assets/fonts/IRANYEKANEXTRABOLD.TTF differ diff --git a/lib/assets/fonts/IRANYEKANLIGHT.TTF b/lib/assets/fonts/IRANYEKANLIGHT.TTF new file mode 100644 index 0000000..a14f579 Binary files /dev/null and b/lib/assets/fonts/IRANYEKANLIGHT.TTF differ diff --git a/lib/assets/fonts/IRANYEKANMEDIUM.TTF b/lib/assets/fonts/IRANYEKANMEDIUM.TTF new file mode 100644 index 0000000..ba6137f Binary files /dev/null and b/lib/assets/fonts/IRANYEKANMEDIUM.TTF differ diff --git a/lib/assets/fonts/IRANYEKANREGULAR.TTF b/lib/assets/fonts/IRANYEKANREGULAR.TTF new file mode 100644 index 0000000..a0fbc0c Binary files /dev/null and b/lib/assets/fonts/IRANYEKANREGULAR.TTF differ diff --git a/lib/assets/fonts/IRANYEKANTHIN.TTF b/lib/assets/fonts/IRANYEKANTHIN.TTF new file mode 100644 index 0000000..2d75fab Binary files /dev/null and b/lib/assets/fonts/IRANYEKANTHIN.TTF differ diff --git a/lib/assets/icons/New Home.svg b/lib/assets/icons/New Home.svg new file mode 100644 index 0000000..5f80613 --- /dev/null +++ b/lib/assets/icons/New Home.svg @@ -0,0 +1,4 @@ + + + + diff --git a/lib/assets/icons/New_Profile.svg b/lib/assets/icons/New_Profile.svg new file mode 100644 index 0000000..4c39612 --- /dev/null +++ b/lib/assets/icons/New_Profile.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/lib/assets/icons/bot.svg b/lib/assets/icons/bot.svg new file mode 100644 index 0000000..e71ba2b --- /dev/null +++ b/lib/assets/icons/bot.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/assets/icons/home.svg b/lib/assets/icons/home.svg new file mode 100644 index 0000000..b2bf433 --- /dev/null +++ b/lib/assets/icons/home.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/assets/icons/live ai.svg b/lib/assets/icons/live ai.svg new file mode 100644 index 0000000..84b0ad0 --- /dev/null +++ b/lib/assets/icons/live ai.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/assets/icons/search sort.svg b/lib/assets/icons/search sort.svg new file mode 100644 index 0000000..6803807 --- /dev/null +++ b/lib/assets/icons/search sort.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/assets/icons/search.svg b/lib/assets/icons/search.svg new file mode 100644 index 0000000..e2d0598 --- /dev/null +++ b/lib/assets/icons/search.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/assets/icons/voice-square.svg b/lib/assets/icons/voice-square.svg new file mode 100644 index 0000000..d5bb1fe --- /dev/null +++ b/lib/assets/icons/voice-square.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/lib/config/theme_data.dart b/lib/config/theme_data.dart index cb60d00..7005c58 100644 --- a/lib/config/theme_data.dart +++ b/lib/config/theme_data.dart @@ -7,9 +7,10 @@ class LightThemeConfig { static const Color _primary = Color(0xFF007EA7); static const Color _white = Color(0xFFFFFFFF); static const Color _black = Color(0xFF292929); - static const Color _background = Color(0xFFF8F8FA); + static const Color _background = Color(0xFFFFFFFF); static ThemeData get themeData => ThemeData( + fontFamily: 'IranYekan', scaffoldBackgroundColor: _background, textTheme: _TextThemeData.data, cardColor: _colorScheme.surface, @@ -53,6 +54,7 @@ class DarkThemeConfig { static const Color _background = Color(0xFF202224); static ThemeData get themeData => ThemeData( + fontFamily: 'IranYekan', scaffoldBackgroundColor: _background, textTheme: _TextThemeData.data, iconTheme: IconThemeData( @@ -97,7 +99,6 @@ class DarkThemeConfig { static const Color hint = Color(0xFFBBBBBB); static const Color border = Color(0xFF666666); - // Error and success static const Color errorLight = Color(0xFFF0C9CD); static const Color error = Color(0xFFF53B3B); static const Color successLight = Color(0xFFBBD6B4); @@ -120,35 +121,41 @@ class _TextThemeData { static TextStyle get _headline3Text => TextStyle( fontSize: 20 * DesignConfig.fontScale, fontWeight: FontWeight.w600, + fontFamily: 'IranYekan', ); static TextStyle get _subtitle1Text => TextStyle( fontSize: 17 * DesignConfig.fontScale, fontWeight: FontWeight.w700, + fontFamily: 'IranYekan', ); static TextStyle get _subtitle2Text => TextStyle( fontSize: 15 * DesignConfig.fontScale, fontWeight: FontWeight.w700, + fontFamily: 'IranYekan', ); static TextStyle get _body1Text => TextStyle( fontSize: 15 * DesignConfig.fontScale, fontWeight: FontWeight.w700, + fontFamily: 'IranYekan', ); static TextStyle get _body2Text => TextStyle( fontSize: 15 * DesignConfig.fontScale, fontWeight: FontWeight.w400, + fontFamily: 'IranYekan', ); static TextStyle get _captionText => TextStyle( fontSize: 13 * DesignConfig.fontScale, fontWeight: FontWeight.w400, + fontFamily: 'IranYekan', ); static TextStyle get _overlineText => TextStyle( fontSize: 12 * DesignConfig.fontScale, fontWeight: FontWeight.w300, + fontFamily: 'IranYekan', ); } extension DidvanColorScheme on ColorScheme { - // Secondary colors Color get secondaryDisabled => brightness == Brightness.dark ? const Color(0xFFFFC8D7) : const Color(0xFF703848); @@ -210,7 +217,6 @@ extension DidvanColorScheme on ColorScheme { : const Color(0xFFffffff); Color get yellow => const Color(0XFFEAA92A); - // Error and success colors Color get errorBack => brightness == Brightness.dark ? const Color(0xFF2B2325) : const Color(0xFFFFF8F8); diff --git a/lib/main.dart b/lib/main.dart index b7c514e..3713923 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,3 @@ -// lib/main.dart - // ignore_for_file: deprecated_member_use import 'dart:async'; diff --git a/lib/models/auth/auth_requests.dart b/lib/models/auth/auth_requests.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/models/auth/user_actions_models.dart b/lib/models/auth/user_actions_models.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/providers/theme.dart b/lib/providers/theme.dart index 8906cc4..7c08ef1 100644 --- a/lib/providers/theme.dart +++ b/lib/providers/theme.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; class ThemeProvider extends CoreProvier { ThemeMode _themeMode = ThemeMode.system; - String _fontFamily = 'Dana-FA'; + String _fontFamily = 'IranYekan'; double _fontScale = 1; set themeMode(ThemeMode value) { diff --git a/lib/services/app_initalizer.dart b/lib/services/app_initalizer.dart index 9ca790d..fb614fa 100644 --- a/lib/services/app_initalizer.dart +++ b/lib/services/app_initalizer.dart @@ -185,7 +185,7 @@ class AppInitializer { ); await StorageService.setValue( key: 'fontFamily', - value: 'Dana-FA', + value: 'IranYekan', ); await StorageService.setValue( key: 'fontSizeScale', @@ -196,7 +196,7 @@ class AppInitializer { value: 'light', ); return SettingsData( - fontFamily: 'Dana-FA', + fontFamily: 'IranYekan', fontScale: 1, themeMode: ThemeMode.light, ); @@ -212,7 +212,7 @@ class AppInitializer { ); await StorageService.setValue( key: 'fontFamily', - value: 'Dana-FA', + value: 'IranYekan', ); await StorageService.setValue( key: 'fontSizeScale', @@ -223,7 +223,7 @@ class AppInitializer { value: 'light', ); return SettingsData( - fontFamily: 'Dana-FA', + fontFamily: 'IranYekan', fontScale: 1, themeMode: ThemeMode.light, ); diff --git a/lib/services/auth/auth_interceptor.dart b/lib/services/auth/auth_interceptor.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/services/auth/auth_service.dart b/lib/services/auth/auth_service.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/services/auth/keycloak_auth_service.dart b/lib/services/auth/keycloak_auth_service.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/services/auth/token_storage.dart b/lib/services/auth/token_storage.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/services/auth/user_actions_service.dart b/lib/services/auth/user_actions_service.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/views/home/home.dart b/lib/views/home/home.dart index 8c4b9cc..4abe08e 100644 --- a/lib/views/home/home.dart +++ b/lib/views/home/home.dart @@ -1,32 +1,19 @@ import 'package:didvan/config/design_config.dart'; -import 'package:didvan/config/theme_data.dart'; -import 'package:didvan/constants/app_icons.dart'; -import 'package:didvan/constants/assets.dart'; -import 'package:didvan/main.dart'; import 'package:didvan/models/notification_message.dart'; import 'package:didvan/models/view/action_sheet_data.dart'; import 'package:didvan/providers/theme.dart'; -import 'package:didvan/routes/routes.dart'; import 'package:didvan/services/app_initalizer.dart'; import 'package:didvan/utils/action_sheet.dart'; -import 'package:didvan/views/ai/ai_state.dart'; -import 'package:didvan/views/ai/ai.dart'; -import 'package:didvan/views/ai/history_ai_chat_state.dart'; -import 'package:didvan/views/ai/widgets/hoshan_drawer.dart'; import 'package:didvan/views/home/categories/categories_page.dart'; import 'package:didvan/views/home/main/main_page.dart'; import 'package:didvan/views/home/home_state.dart'; import 'package:didvan/views/home/new_statistic/new_statistic.dart'; import 'package:didvan/views/home/search/search.dart'; import 'package:didvan/views/widgets/didvan/text.dart'; -import 'package:didvan/views/widgets/hoshan_app_bar.dart'; -import 'package:didvan/views/widgets/ink_wrapper.dart'; -import 'package:didvan/views/widgets/logo_app_bar.dart'; import 'package:didvan/views/widgets/didvan/bnb.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_svg/svg.dart'; import 'package:provider/provider.dart'; import '../../services/app_home_widget/home_widget_repository.dart'; @@ -53,20 +40,11 @@ class _HomeState extends State final state = context.read(); DesignConfig.updateSystemUiOverlayStyle(); - _tabController = TabController(length: 4, vsync: this, initialIndex: 0); + _tabController = TabController(length: 3, vsync: this, initialIndex: 0); state.tabController = _tabController; _tabController.addListener(() { state.currentPageIndex = _tabController.index; - if (_tabController.index == 3) { - // Changed from 2 to 3 for Houshan tab - // با هر بار ورود به تب هوشان، لیست چت‌ها ریست می‌شود - final historyState = context.read(); - historyState.chats.clear(); - historyState.archivedChats.clear(); - historyState.update(); // برای اطمینان از به‌روزرسانی UI - historyState.getBots(); - } }); if (!kIsWeb) { Future.delayed(Duration.zero, () { @@ -87,33 +65,17 @@ class _HomeState extends State super.initState(); } - PreferredSizeWidget getAppBar() { - // Show HoshanAppBar only for AI section (index 3) - if (context.watch().tabController.index == 3) { - return HoshanAppBar( - onBack: () { - final state = context.read(); - if (state.page == 1) { - state.goToAi(); - } - }, - ); - } - // For all other tabs (home, categories, statistics), show LogoAppBar - return const LogoAppBar(); + PreferredSizeWidget? getAppBar() { + return null; } @override Widget build(BuildContext context) { return Scaffold( key: homeScaffKey, - appBar: getAppBar(), + backgroundColor: Theme.of(context).colorScheme.background, resizeToAvoidBottomInset: false, - drawer: context.watch().tabController.index == 2 - ? HoshanDrawer( - scaffKey: homeScaffKey, - ) - : null, + drawer: null, // ignore: deprecated_member_use body: WillPopScope( onWillPop: () async { @@ -133,16 +95,6 @@ class _HomeState extends State confrimTitle: 'بله', dismissTitle: 'خیر', )); - } else if (context.read().tabController.index == 3) { - // Changed from 2 to 3 - switch (context.read().page) { - case 1: - context.read().goToAi(); - break; - - default: - _tabController.animateTo(0); - } } else { _tabController.animateTo(0); } @@ -164,7 +116,6 @@ class _HomeState extends State MainPage(), CategoriesPage(), NewStatistic(), - Ai(), ], ), ), diff --git a/lib/views/home/main/main_page.dart b/lib/views/home/main/main_page.dart index 182e73b..793e1a8 100644 --- a/lib/views/home/main/main_page.dart +++ b/lib/views/home/main/main_page.dart @@ -1,5 +1,6 @@ import 'package:didvan/config/theme_data.dart'; import 'package:didvan/constants/app_icons.dart'; +import 'package:didvan/constants/assets.dart'; import 'package:didvan/main.dart'; import 'package:didvan/models/home_page_content/home_page_list.dart'; import 'package:didvan/models/home_page_content/swot.dart'; @@ -14,6 +15,14 @@ import 'package:didvan/views/home/main/widgets/story_section.dart'; import 'package:didvan/views/widgets/didvan/slider.dart'; import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:didvan/views/widgets/state_handlers/state_handler.dart'; +import 'package:didvan/views/widgets/search_field.dart'; +import 'package:didvan/views/home/home_state.dart'; +import 'package:didvan/utils/action_sheet.dart'; +import 'package:didvan/models/view/action_sheet_data.dart'; +import 'package:didvan/views/widgets/didvan/checkbox.dart'; +import 'package:didvan/views/widgets/text_divider.dart'; +import 'package:didvan/views/widgets/item_title.dart'; +import 'package:didvan/views/widgets/date_picker_button.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -23,13 +32,10 @@ import 'package:url_launcher/url_launcher_string.dart'; import 'package:didvan/views/home/main/widgets/swot_item_card.dart'; import 'package:flutter/foundation.dart' show kIsWeb, defaultTargetPlatform; -import 'package:flutter/material.dart'; // برای دسترسی به TargetPlatform // این پکیج فقط برای نسخه وب استفاده می‌شود import 'package:universal_html/html.dart' as html; -/// تشخیص می‌دهد که آیا دستگاه یک موبایل است (چه نیتیو و چه وب) bool isAnyMobile() { - // اگر کد روی وب در حال اجراست if (kIsWeb) { final userAgent = html.window.navigator.userAgent.toLowerCase(); return userAgent.contains('mobile') || @@ -37,8 +43,6 @@ bool isAnyMobile() { userAgent.contains('ios'); } - // اگر کد روی پلتفرم نیتیو در حال اجراست - // defaultTargetPlatform پلتفرم اصلی (مثلا اندروید یا iOS) را برمی‌گرداند return defaultTargetPlatform == TargetPlatform.android || defaultTargetPlatform == TargetPlatform.iOS; } @@ -79,11 +83,73 @@ class _MainPageState extends State { print( "DEBUG: FutureBuilder state.content!.lists.isNotEmpty: ${state.content!.lists.isNotEmpty}"); return ListView( - padding: const EdgeInsets.symmetric(vertical: 16), + padding: const EdgeInsets.only(top: 0, bottom: 16), children: [ - if (state.stories.isNotEmpty) StorySection(stories: state.stories), + Padding( + padding: const EdgeInsets.fromLTRB(16, 0, 16, 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SvgPicture.asset( + Assets.horizontalLogoWithText, + height: 60, + color: Theme.of(context).colorScheme.title, + ), + GestureDetector( + onTap: () { + Navigator.pushNamed(context, Routes.profile); + }, + child: SizedBox( + width: 44, + height: 44, + child: Center( + child: SvgPicture.asset( + 'lib/assets/icons/New_Profile.svg', + width: 30, + height: 30, + color: Theme.of(context).colorScheme.title, + ), + ), + ), + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(16, 0, 16, 16), + child: SearchField( + title: 'دیدوان', + focusNode: context.read().searchFieldFocusNode, + onChanged: (value) { + final homeState = context.read(); + homeState.search = value; + if (value.length >= 3) { + homeState.searchAll(page: 1); + } + }, + onFilterButtonPressed: () => _showFilterBottomSheet(context), + isFiltered: context.watch().filtering, + value: context.watch().search, + extraIconPath: 'lib/assets/icons/profile.svg', + onExtraIconPressed: () { + print('Extra icon pressed!'); + }, + ), + ), + if (state.stories.isNotEmpty) ...[ + const TextDivider(text: 'دیده‌بان'), + const _DidvanSignalsTitle(), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: StorySection(stories: state.stories), + ), + ], const SizedBox(height: 12), - const MainPageMainContent(), + const TextDivider(text: 'پیشخوان استراتژیک'), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 16), + child: MainPageMainContent(), + ), Builder(builder: (context) { final List pageContent = []; if (state.content != null && state.content!.lists.isNotEmpty) { @@ -117,17 +183,10 @@ class _MainPageState extends State { child: Row( children: [ DidvanText( - "همه", - color: Theme.of(context) - .colorScheme - .primary, + "مشاهده همه", + color: Theme.of(context).colorScheme.primary, + fontWeight: FontWeight.bold, ), - Icon( - DidvanIcons.angle_left_light, - color: Theme.of(context) - .colorScheme - .primary, - ) ], ), ) @@ -161,6 +220,81 @@ class _MainPageState extends State { }, ); } + + Future _showFilterBottomSheet(BuildContext context) async { + final state = Provider.of(context, listen: false); + + ActionSheetUtils(context).showBottomSheet( + data: ActionSheetData( + titleIcon: DidvanIcons.filter_regular, + dismissTitle: 'حذف فیلتر', + confrimTitle: 'نمایش نتایج', + onDismissed: () => state.resetFilters(false), + onConfirmed: () => state.searchAll(page: 1), + content: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (state.currentPageIndex != 3) ...[ + ItemTitle( + title: 'تاریخ ایجاد', + style: Theme.of(context).textTheme.bodyMedium, + icon: DidvanIcons.calendar_range_regular, + ), + const SizedBox(height: 8), + StatefulBuilder( + builder: (context, setState) => Row( + children: [ + DatePickerButton( + initialValue: state.startDate, + emptyText: 'از تاریخ', + onPicked: (date) => + setState(() => state.startDate = date), + lastDate: state.endDate, + ), + const SizedBox(width: 8), + DatePickerButton( + initialValue: state.endDate, + emptyText: 'تا تاریخ', + onPicked: (date) => setState(() => state.endDate = date), + firstDate: state.startDate, + ), + ], + ), + ), + const SizedBox(height: 28), + ], + ItemTitle( + title: 'دسته بندی', + icon: DidvanIcons.category_regular, + style: Theme.of(context).textTheme.bodyMedium, + ), + const SizedBox(height: 12), + Wrap( + children: [ + for (var i = 0; i < state.categoryFilters.length; i++) + if (state.categoryFilters[i].label != 'هوشان') + SizedBox( + width: (MediaQuery.of(context).size.width - 40) / 2, + child: DidvanCheckbox( + title: state.categoryFilters[i].label, + value: state.selectedCats + .contains(state.categoryFilters[i]), + onChanged: (value) { + if (value) { + state.selectedCats.add(state.categoryFilters[i]); + return; + } + state.selectedCats.remove(state.categoryFilters[i]); + }, + ), + ), + ], + ), + ], + ), + ), + ); + } } class _SwotSection extends StatelessWidget { @@ -188,6 +322,7 @@ class _SwotSection extends StatelessWidget { children: [ SvgPicture.asset( "lib/assets/images/features/Saha Solid.svg", + color: Theme.of(context).colorScheme.title, ), const SizedBox(width: 5), DidvanText( @@ -206,16 +341,13 @@ class _SwotSection extends StatelessWidget { ); }, child: Padding( - padding: const EdgeInsets.only(left: 20), + padding: EdgeInsets.only(left: 20), child: Row( children: [ DidvanText( - "همه", - color: Theme.of(context).colorScheme.primary, - ), - Icon( - DidvanIcons.angle_left_light, + "مشاهده همه", color: Theme.of(context).colorScheme.primary, + fontWeight: FontWeight.bold, ), ], ), @@ -253,7 +385,10 @@ class InfoTitle extends StatelessWidget { Widget build(BuildContext context) { return Row( children: [ - const Icon(DidvanIcons.infography_solid), + Icon( + DidvanIcons.infography_solid, + color: Theme.of(context).colorScheme.title, + ), const SizedBox(width: 4), DidvanText( "اینفوگرافی", @@ -265,6 +400,39 @@ class InfoTitle extends StatelessWidget { } } +class _DidvanSignalsTitle extends StatelessWidget { + const _DidvanSignalsTitle(); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only( + left: 16, + right: 16, + bottom: 16, + top: 0, + ), + child: Row( + children: [ + SvgPicture.asset( + 'lib/assets/icons/voice-square.svg', + color: Theme.of(context).colorScheme.title, + width: 30, + height: 30, + ), + const SizedBox(width: 5), + DidvanText( + "سیگنال‌های دیدوان", + style: Theme.of(context).textTheme.titleMedium, + color: Theme.of(context).colorScheme.title, + fontSize: 13, + ), + ], + ), + ); + } +} + class _MainPageSection extends StatelessWidget { final MainPageList list; final bool isLast; @@ -356,7 +524,11 @@ class _MainPageSection extends StatelessWidget { children: [ Row( children: [ - if (icon != null) Icon(icon), + if (icon != null) + Icon( + icon, + color: Theme.of(context).colorScheme.title, + ), const SizedBox(width: 4), DidvanText( list.header, @@ -370,13 +542,10 @@ class _MainPageSection extends StatelessWidget { child: Row( children: [ DidvanText( - list.more, + "مشاهده همه", color: Theme.of(context).colorScheme.primary, + fontWeight: FontWeight.bold, ), - Icon( - DidvanIcons.angle_left_light, - color: Theme.of(context).colorScheme.primary, - ) ], ), ) @@ -411,10 +580,7 @@ class _MainPageSection extends StatelessWidget { return DidvanSlider( height: 260 + (_maxSublistCount() - (list.type == 'radar' ? 1 : 0)) * 20, itemCount: list.contents.length, - // -- START: کد اصلاح شده در اینجا قرار دارد -- - // از isMobile() برای تنظیم اندازه آیتم‌ها بر اساس موبایل یا دسکتاپ بودن استفاده می‌کنیم viewportFraction: isAnyMobile() ? 0.65 : 0.55, - // -- END: کد اصلاح شده -- itemBuilder: (context, index, realIndex) => Padding( padding: const EdgeInsets.symmetric(horizontal: 4), child: MainPageGeneralItem( diff --git a/lib/views/home/main/widgets/story_section.dart b/lib/views/home/main/widgets/story_section.dart index 9d26a91..49d75c5 100644 --- a/lib/views/home/main/widgets/story_section.dart +++ b/lib/views/home/main/widgets/story_section.dart @@ -1,6 +1,7 @@ import 'package:didvan/models/story_model.dart'; import 'package:didvan/routes/routes.dart'; import 'package:flutter/material.dart'; +import 'package:didvan/config/theme_data.dart'; class StorySection extends StatelessWidget { final List stories; @@ -47,11 +48,9 @@ class _StoryCircle extends StatelessWidget { @override Widget build(BuildContext context) { - // ValueNotifier برای پیگیری وضعیت مشاهده همه استوری‌ها final allStoriesViewed = ValueNotifier( userStories.stories.every((story) => story.isViewed.value)); - // افزودن Listener به هر استوری for (var story in userStories.stories) { story.isViewed.addListener(() { allStoriesViewed.value = @@ -64,26 +63,27 @@ class _StoryCircle extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - // استفاده از ValueListenableBuilder برای تغییر رنگ حاشیه ValueListenableBuilder( valueListenable: allStoriesViewed, builder: (context, isViewed, child) { - return Container( - width: 85.0, - height: 85.0, + return Hero( + tag: userStories.user.name, + child: Container( + width: 85.0, + height: 85.0, decoration: BoxDecoration( shape: BoxShape.circle, gradient: isViewed - ? const LinearGradient( + ? LinearGradient( colors: [ - Color.fromARGB(255, 184, 184, 184), - Color.fromARGB(255, 184, 184, 184) + Theme.of(context).colorScheme.cardBorder, + Theme.of(context).colorScheme.cardBorder, ], ) - : const LinearGradient( + : LinearGradient( colors: [ - Color.fromARGB(255, 1, 35, 54), - Color.fromARGB(255, 178, 4, 54), + Theme.of(context).colorScheme.primary, + Theme.of(context).colorScheme.primary, ], begin: Alignment.topRight, end: Alignment.bottomLeft, @@ -92,25 +92,24 @@ class _StoryCircle extends StatelessWidget { child: Padding( padding: const EdgeInsets.all(4.0), child: Container( - decoration: const BoxDecoration( - color: Colors.white, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, shape: BoxShape.circle, ), child: Padding( padding: const EdgeInsets.all(4.0), child: CircleAvatar( - backgroundColor: - const Color.fromARGB(255, 230, 242, 246), + backgroundColor: Theme.of(context).colorScheme.splash, child: ClipOval( child: Image.asset( userStories.user - .profileImageUrl, // Assuming this is a local asset + .profileImageUrl, fit: BoxFit.cover, width: 50.0, height: 50.0, errorBuilder: (context, error, stackTrace) { - return const Icon(Icons.person, - color: Colors.grey, size: 40.0); + return Icon(Icons.person, + color: Theme.of(context).colorScheme.caption, size: 40.0); }, ), ), @@ -118,6 +117,7 @@ class _StoryCircle extends StatelessWidget { ), ), ), + ), ); }, ), diff --git a/lib/views/home/search/widgets/search_result_item.dart b/lib/views/home/search/widgets/search_result_item.dart index 284248a..89371bc 100644 --- a/lib/views/home/search/widgets/search_result_item.dart +++ b/lib/views/home/search/widgets/search_result_item.dart @@ -173,7 +173,7 @@ class SearchResultItem extends StatelessWidget { const SizedBox(width: 8), Expanded( child: SizedBox( - height: 80, + height: 200, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, diff --git a/lib/views/home/widgets/categories.dart b/lib/views/home/widgets/categories.dart index 77e9c22..9ac65d2 100644 --- a/lib/views/home/widgets/categories.dart +++ b/lib/views/home/widgets/categories.dart @@ -12,7 +12,18 @@ import 'package:url_launcher/url_launcher_string.dart'; class MainCategories extends StatelessWidget { const MainCategories({super.key}); - void _onTap(String link, BuildContext context) { + void _onTap(String link, String label, BuildContext context) { // label را اضافه کنید + // اگر روی "آمار و داده" کلیک شد، مستقیم به تب مربوطه برود + if (label == 'آمار و داده') { + final state = context.read(); + // فرض ما این است که صفحه آمار و داده در ایندکس 2 قرار دارد + // اگر ایندکس دیگری است، آن را تغییر دهید + const statsPageIndex = 2; + state.currentPageIndex = statsPageIndex; + state.tabController.animateTo(statsPageIndex); + return; // از ادامه اجرای کد جلوگیری می‌کند + } + if (link.startsWith('http')) { AppInitializer.openWebLink( context, @@ -39,10 +50,9 @@ class MainCategories extends StatelessWidget { children: state.menuItems .map( (e) => GestureDetector( - onTap: () => _onTap(e.link, context), + onTap: () => _onTap(e.link, e.label, context), // لیبل را اینجا پاس دهید child: SizedBox( - width: (MediaQuery.of(context).size.width) / 4, - // (MediaQuery.of(context).size.width - 40) / 3, + width: (MediaQuery.of(context).size.width) / 4, child: Column( children: [ Container( @@ -72,4 +82,4 @@ class MainCategories extends StatelessWidget { .toList(), ); } -} +} \ No newline at end of file diff --git a/lib/views/profile/general_settings/settings.dart b/lib/views/profile/general_settings/settings.dart index c7cad4d..531cc30 100644 --- a/lib/views/profile/general_settings/settings.dart +++ b/lib/views/profile/general_settings/settings.dart @@ -103,8 +103,11 @@ class _GeneralSettingsState extends State { child: Column( children: [ MenuOption( - suffix: - state.fontFamily == 'Dana-FA' ? 'دانا' : 'ایران سنس', + suffix: state.fontFamily == 'Dana-FA' + ? 'دانا' + : state.fontFamily == 'Iransans-FA' + ? 'ایران سنس' + : 'ایران یکان', title: 'فونت برنامه', onTap: _showFontFamilyBottomSheet, ), @@ -164,6 +167,16 @@ class _GeneralSettingsState extends State { }, value: state.fontFamily == 'Iransans-FA', ), + const SizedBox(height: 24), + DidvanRadialButton( + title: 'ایران یکان', + fontFamily: 'IranYekan', + onSelected: () { + state.fontFamily = 'IranYekan'; + setState(() {}); + }, + value: state.fontFamily == 'IranYekan', + ), ], ), ), diff --git a/lib/views/profile/general_settings/settings_state.dart b/lib/views/profile/general_settings/settings_state.dart index d06a0f2..fb5e188 100644 --- a/lib/views/profile/general_settings/settings_state.dart +++ b/lib/views/profile/general_settings/settings_state.dart @@ -11,7 +11,7 @@ class GeneralSettingsState extends CoreProvier { } List _notificationTimeRange = [0, 24]; - String _fontFamily = 'Dana-FA'; + String _fontFamily = 'IranYekan'; double _fontSizeScale = 1; String _brightness = 'light'; String time = ""; diff --git a/lib/views/profile/profile.dart b/lib/views/profile/profile.dart index 75c4eeb..51e7052 100644 --- a/lib/views/profile/profile.dart +++ b/lib/views/profile/profile.dart @@ -139,9 +139,11 @@ class _ProfilePageState extends State { padding: const EdgeInsets.symmetric( vertical: 12.0), child: MenuOption( - suffix: state.fontFamily == 'Dana-FA' - ? 'دانا' - : 'ایران سنس', + suffix: state.fontFamily == 'Dana-FA' + ? 'دانا' + : state.fontFamily == 'Iransans-FA' + ? 'ایران سنس' + : 'ایران یکان', title: 'فونت برنامه', onTap: _showFontFamilyBottomSheet, icon: DidvanIcons.font_regular, @@ -394,6 +396,16 @@ class _ProfilePageState extends State { }, value: state.fontFamily == 'Iransans-FA', ), + const SizedBox(height: 24), + DidvanRadialButton( + title: 'ایران یکان', + fontFamily: 'IranYekan', + onSelected: () { + state.fontFamily = 'IranYekan'; + setState(() {}); + }, + value: state.fontFamily == 'IranYekan', + ), ], ), ), diff --git a/lib/views/splash/splash.dart b/lib/views/splash/splash.dart index 6ac155c..7733bfc 100644 --- a/lib/views/splash/splash.dart +++ b/lib/views/splash/splash.dart @@ -1,4 +1,5 @@ import 'package:didvan/config/design_config.dart'; +import 'package:didvan/config/theme_data.dart'; import 'package:didvan/constants/assets.dart'; import 'package:didvan/main.dart'; import 'package:didvan/providers/media.dart'; @@ -9,7 +10,6 @@ import 'package:didvan/routes/routes.dart'; import 'package:didvan/services/app_initalizer.dart'; import 'package:didvan/services/network/request.dart'; import 'package:didvan/services/storage/storage.dart'; -import 'package:didvan/views/widgets/didvan/button.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -24,16 +24,35 @@ class Splash extends StatefulWidget { State createState() => _SplashState(); } -class _SplashState extends State { +class _SplashState extends State with TickerProviderStateMixin { bool _errorOccured = false; late ThemeProvider themeProvider; late UserProvider userProvider; late MediaProvider mediaProvider; + late AnimationController _pulseController; + late Animation _pulseAnimation; @override void initState() { super.initState(); + // Initialize animation controller + _pulseController = AnimationController( + duration: const Duration(milliseconds: 1500), + vsync: this, + ); + + _pulseAnimation = Tween( + begin: 1.0, + end: 1.1, + ).animate(CurvedAnimation( + parent: _pulseController, + curve: Curves.easeInOut, + )); + + // Start pulse animation + _pulseController.repeat(reverse: true); + themeProvider = context.read(); userProvider = context.read(); mediaProvider = context.read(); @@ -41,42 +60,211 @@ class _SplashState extends State { _initialize(themeProvider, userProvider, mediaProvider); } + @override + void dispose() { + _pulseController.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { + final colorScheme = Theme.of(context).colorScheme; + final isDark = Theme.of(context).brightness == Brightness.light; + return AnnotatedRegion( value: DesignConfig.systemUiOverlayStyle.copyWith( - systemNavigationBarColor: Theme.of(context).colorScheme.background, + systemNavigationBarColor: colorScheme.background, + statusBarColor: Colors.transparent, + statusBarIconBrightness: isDark ? Brightness.light : Brightness.dark, ), - child: Material( - child: Container( - alignment: Alignment.center, - padding: const EdgeInsets.symmetric(horizontal: 48, vertical: 60), - color: Theme.of(context).colorScheme.background, - child: Column( + child: Scaffold( + backgroundColor: colorScheme.background, + body: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + colorScheme.background, + colorScheme.background.withOpacity(0.8), + colorScheme.primary.withOpacity(0.05), + ], + ), + ), + child: Stack( children: [ - const SizedBox(height: 70), - SvgPicture.asset( - Assets.horizontalLogoWithText, + // Floating particles background + _buildFloatingParticles(colorScheme), + + SafeArea( + child: Column( + children: [ + // Top section with logo + Expanded( + flex: 3, + child: Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(horizontal: 32), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // Logo with subtle animation + TweenAnimationBuilder( + duration: const Duration(milliseconds: 800), + tween: Tween(begin: 0.0, end: 1.0), + builder: (context, value, child) { + return Transform.scale( + scale: 0.7 + (0.3 * value), + child: Opacity( + opacity: value, + child: AnimatedBuilder( + animation: _pulseAnimation, + builder: (context, child) { + return Transform.scale( + scale: _pulseAnimation.value, + child: Container( + padding: const EdgeInsets.all(24), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + gradient: RadialGradient( + colors: [ + colorScheme.primary.withOpacity(0.05), + Colors.transparent, + ], + ), + boxShadow: [ + BoxShadow( + color: colorScheme.primary.withOpacity(0.15), + blurRadius: 30, + spreadRadius: 8, + offset: const Offset(0, 15), + ), + ], + ), + child: SvgPicture.asset( + Assets.horizontalLogoWithText, + height: 80, + ), + ), + ); + }, + ), + ), + ); + }, + ), + ], + ), + ), + ), + + // Bottom section with loading/error + Expanded( + flex: 2, + child: Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(horizontal: 48), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (!_errorOccured) ...[ + // Modern loading indicator + _buildModernLoader(colorScheme), + const SizedBox(height: 24), + // Loading text with fade animation + AnimatedBuilder( + animation: _pulseController, + builder: (context, child) { + return Opacity( + opacity: 0.4 + (0.4 * _pulseController.value), + child: Text( + 'در حال بارگذاری...', + style: TextStyle( + fontSize: 16, + color: colorScheme.checkFav.withOpacity(0.7), + fontWeight: FontWeight.w400, + letterSpacing: 0.8, + ), + ), + ); + }, + ), + ], + + if (_errorOccured) ...[ + // Error state with simple and clean design + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // Simple error icon + Container( + width: 60, + height: 60, + decoration: BoxDecoration( + color: colorScheme.error.withOpacity(0.1), + borderRadius: BorderRadius.circular(30), + ), + child: Icon( + Icons.wifi_off_rounded, + size: 28, + color: colorScheme.error, + ), + ), + const SizedBox(height: 20), + // Clean error message + Text( + 'مشکل در اتصال', + style: TextStyle( + fontSize: 16, + color: colorScheme.checkFav, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 8), + Text( + 'لطفاً اتصال خود را بررسی کنید', + style: TextStyle( + fontSize: 14, + color: colorScheme.checkFav.withOpacity(0.6), + fontWeight: FontWeight.w400, + ), + ), + const SizedBox(height: 24), + // Simple retry button + _buildRetryButton(colorScheme), + ], + ), + ], + ], + ), + ), + ), + + // Brand tagline at bottom + Padding( + padding: const EdgeInsets.only(bottom: 32), + child: TweenAnimationBuilder( + duration: const Duration(milliseconds: 1000), + tween: Tween(begin: 0.0, end: 1.0), + builder: (context, value, child) { + return Opacity( + opacity: value * 0.6, + child: Text( + 'توسعه یافته توسط فرتاک', + style: TextStyle( + fontSize: 14, + color: colorScheme.checkFav, + fontWeight: FontWeight.w500, + letterSpacing: 1, + ), + ), + ); + }, + ), + ), + ], + ), ), - if (!_errorOccured) - Image.asset( - Assets.loadingAnimation, - width: 60, - height: 60, - ), - if (_errorOccured) const SizedBox(height: 30), - if (_errorOccured) - DidvanButton( - width: 120, - height: 40, - title: 'تلاش مجدد', - onPressed: () { - setState(() { - _errorOccured = false; - }); - _initialize(themeProvider, userProvider, mediaProvider); - }, - ), ], ), ), @@ -84,6 +272,122 @@ class _SplashState extends State { ); } + Widget _buildFloatingParticles(ColorScheme colorScheme) { + return AnimatedBuilder( + animation: _pulseController, + builder: (context, child) { + return Stack( + children: [ + // Particle 1 + Positioned( + top: 100 + (20 * _pulseController.value), + right: 50 + (10 * _pulseController.value), + child: Container( + width: 6, + height: 6, + decoration: BoxDecoration( + color: colorScheme.primary.withOpacity(0.3), + shape: BoxShape.circle, + ), + ), + ), + // Particle 2 + Positioned( + top: 200 + (15 * (1 - _pulseController.value)), + left: 80 + (8 * _pulseController.value), + child: Container( + width: 4, + height: 4, + decoration: BoxDecoration( + color: colorScheme.secondary.withOpacity(0.4), + shape: BoxShape.circle, + ), + ), + ), + // Particle 3 + Positioned( + bottom: 180 + (25 * _pulseController.value), + right: 100 + (12 * (1 - _pulseController.value)), + child: Container( + width: 8, + height: 8, + decoration: BoxDecoration( + color: colorScheme.primary.withOpacity(0.2), + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: colorScheme.primary.withOpacity(0.1), + blurRadius: 10, + spreadRadius: 3, + ), + ], + ), + ), + ), + // Particle 4 + Positioned( + bottom: 120 + (18 * (1 - _pulseController.value)), + left: 60 + (15 * _pulseController.value), + child: Container( + width: 5, + height: 5, + decoration: BoxDecoration( + color: colorScheme.tertiary.withOpacity(0.35), + shape: BoxShape.circle, + ), + ), + ), + ], + ); + }, + ); + } + + Widget _buildModernLoader(ColorScheme colorScheme) { + // استفاده از loading animation اصلی و قدیمی دیدوان + return SizedBox( + width: 60, + height: 60, + child: Image.asset( + Assets.loadingAnimation, + width: 60, + height: 60, + fit: BoxFit.contain, + ), + ); + } + + Widget _buildRetryButton(ColorScheme colorScheme) { + return SizedBox( + width: 140, + height: 44, + child: ElevatedButton( + onPressed: () { + setState(() { + _errorOccured = false; + }); + _initialize(themeProvider, userProvider, mediaProvider); + }, + style: ElevatedButton.styleFrom( + backgroundColor: colorScheme.primary, + foregroundColor: colorScheme.onPrimary, + elevation: 0, + shadowColor: Colors.transparent, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(22), + ), + ), + child: const Text( + 'تلاش مجدد', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + ), + ), + ), + ); + } + Future _initialize(ThemeProvider themeProvider, UserProvider userProvider, MediaProvider mediaProvider) async { try { diff --git a/lib/views/story_viewer/story_viewer_page.dart b/lib/views/story_viewer/story_viewer_page.dart index 28af012..dbb340c 100644 --- a/lib/views/story_viewer/story_viewer_page.dart +++ b/lib/views/story_viewer/story_viewer_page.dart @@ -1,5 +1,3 @@ -// lib/views/story_viewer/story_viewer_page.dart - import 'package:cached_network_image/cached_network_image.dart'; import 'package:didvan/models/story_model.dart'; import 'package:didvan/services/story_service.dart'; @@ -23,11 +21,21 @@ class StoryViewerPage extends StatefulWidget { class _StoryViewerPageState extends State { late PageController _pageController; + double _currentPage = 0.0; @override void initState() { super.initState(); - _pageController = PageController(initialPage: widget.tappedIndex); + _pageController = PageController( + initialPage: widget.tappedIndex, + viewportFraction: 0.999, + ); + _currentPage = widget.tappedIndex.toDouble(); + _pageController.addListener(() { + setState(() { + _currentPage = _pageController.page!; + }); + }); } @override @@ -46,19 +54,30 @@ class _StoryViewerPageState extends State { itemCount: widget.stories.length, itemBuilder: (context, index) { final userStories = widget.stories[index]; - return UserStoryViewer( - key: ValueKey(userStories.user.name + index.toString()), - userStories: userStories, - onComplete: () { - if (index < widget.stories.length - 1) { - _pageController.nextPage( - duration: const Duration(milliseconds: 300), - curve: Curves.easeIn, - ); - } else { - Navigator.of(context).pop(); - } - }, + final value = _currentPage - index; + final rotationY = value * 0.8; + final transform = Matrix4.identity() + ..setEntry(3, 2, 0.001) + ..rotateY(rotationY); + + return Transform( + alignment: + value > 0 ? Alignment.centerRight : Alignment.centerLeft, + transform: transform, + child: UserStoryViewer( + key: ValueKey(userStories.user.name + index.toString()), + userStories: userStories, + onComplete: () { + if (index < widget.stories.length - 1) { + _pageController.nextPage( + duration: const Duration(milliseconds: 300), + curve: Curves.easeIn, + ); + } else { + Navigator.of(context).pop(); + } + }, + ), ); }, ), @@ -321,42 +340,20 @@ class _AnimatedBar extends StatelessWidget { Widget build(BuildContext context) { return Flexible( child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 1.5), - child: LayoutBuilder( - builder: (context, constraints) { - return Stack( - children: [ - Container( - height: 6.0, - width: double.infinity, - decoration: BoxDecoration( - color: position < currentIndex - ? Colors.white - // ignore: deprecated_member_use - : Colors.white.withOpacity(0.5), - border: Border.all(color: Colors.black26, width: 0.8), - borderRadius: BorderRadius.circular(30.0), - ), - ), - if (position == currentIndex) - Align( - alignment: Alignment.centerLeft, - child: AnimatedBuilder( - animation: animationController, - builder: (context, child) { - return Container( - height: 6.0, - width: - constraints.maxWidth * animationController.value, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(30.0), - ), - ); - }, - ), - ), - ], + padding: const EdgeInsets.symmetric(horizontal: 2.0), + child: AnimatedBuilder( + animation: animationController, + builder: (context, child) { + return LinearProgressIndicator( + value: (position < currentIndex) + ? 1.0 + : (position == currentIndex + ? animationController.value + : 0.0), + backgroundColor: Colors.white.withOpacity(0.5), + valueColor: const AlwaysStoppedAnimation(Colors.white), + minHeight: 4.0, + borderRadius: BorderRadius.circular(30.0), ); }, ), diff --git a/lib/views/widgets/didvan/bnb.dart b/lib/views/widgets/didvan/bnb.dart index 9f557a0..b4faec8 100644 --- a/lib/views/widgets/didvan/bnb.dart +++ b/lib/views/widgets/didvan/bnb.dart @@ -4,6 +4,7 @@ import 'package:didvan/constants/app_icons.dart'; import 'package:didvan/routes/routes.dart'; import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import '../audio/player_navbar.dart'; @@ -31,26 +32,17 @@ class DidvanBNB extends StatelessWidget { decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, borderRadius: - const BorderRadius.vertical(top: Radius.circular(16)), - boxShadow: [ - BoxShadow( - color: const Color(0XFF1B3C59).withValues(alpha: 0.15), - blurRadius: 8, - spreadRadius: 0, - offset: const Offset(0, -8), - ) - ], + const BorderRadius.vertical(top: Radius.circular(0)), + border: const Border( + top: BorderSide( + color: const Color.fromARGB(255, 224, 224, 224), + width: 1.5, + ), + ), ), padding: const EdgeInsets.symmetric(horizontal: 12), child: Row( children: [ - _NavBarItem( - isSelected: currentTabIndex == 0, - title: 'خانه', - selectedIcon: DidvanIcons.house_solid, - unselectedIcon: DidvanIcons.house_light, - onTap: () => onTabChanged(0), - ), _NavBarItem( isSelected: currentTabIndex == 1, title: 'دسته‌بندی', @@ -58,19 +50,56 @@ class DidvanBNB extends StatelessWidget { unselectedIcon: DidvanIcons.category_light, onTap: () => onTabChanged(1), ), - _NavBarItem( + + _NavBarItem( isSelected: false, title: 'هوشان', selectedIcon: DidvanIcons.ai_solid, unselectedIcon: DidvanIcons.ai_regular, onTap: () => Navigator.of(context).pushNamed(Routes.aiSection), + customLogo: SvgPicture.asset( + DesignConfig.isDark + ? 'assets/images/logos/logo-vertical-dark.svg' + : 'lib/assets/icons/bot.svg', + width: 32, + height: 32, + ), ), _NavBarItem( + isSelected: currentTabIndex == 0, + title: 'خانه', + selectedIcon: DidvanIcons.house_solid, + unselectedIcon: DidvanIcons.house_light, + onTap: () => onTabChanged(0), + isHomeButton: true, + customLogo: SvgPicture.asset( + DesignConfig.isDark + ? 'assets/images/logos/logo-vertical-dark.svg' + : 'lib/assets/icons/New Home.svg', + width: 32, + height: 32, + ), + ), + _NavBarItem( isSelected: currentTabIndex == 2, title: 'آمار و داده', selectedIcon: DidvanIcons.stats__solid, unselectedIcon: DidvanIcons.stats__light, onTap: () => onTabChanged(2), + customLogo: SvgPicture.asset( + DesignConfig.isDark + ? 'assets/images/logos/logo-vertical-dark.svg' + : 'lib/assets/icons/bot.svg', + width: 32, + height: 32, + ), + ), + _NavBarItem( + isSelected: false, + title: 'پروفایل', + selectedIcon: DidvanIcons.profile_solid, + unselectedIcon: DidvanIcons.profile_light, + onTap: () => Navigator.of(context).pushNamed(Routes.profile), ), ], ), @@ -87,6 +116,8 @@ class _NavBarItem extends StatelessWidget { final String title; final IconData selectedIcon; final IconData unselectedIcon; + final bool isHomeButton; + final Widget? customLogo; const _NavBarItem({ Key? key, @@ -95,6 +126,8 @@ class _NavBarItem extends StatelessWidget { required this.selectedIcon, required this.unselectedIcon, required this.onTap, + this.isHomeButton = false, + this.customLogo, }) : super(key: key); @override @@ -116,28 +149,35 @@ class _NavBarItem extends StatelessWidget { const SizedBox( height: 4, ), - AnimatedContainer( - padding: const EdgeInsets.all(4), - duration: DesignConfig.lowAnimationDuration, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: isSelected - ? Theme.of(context).colorScheme.focused - : Theme.of(context).colorScheme.surface, + if (isHomeButton && customLogo != null) ...[ + AnimatedContainer( + padding: const EdgeInsets.all(8), + duration: DesignConfig.lowAnimationDuration, + child: SizedBox( + width: 50, + height: 50, + child: customLogo, + ), ), - child: Icon( - isSelected ? selectedIcon : unselectedIcon, - size: 32, - color: DesignConfig.isDark - ? Theme.of(context).colorScheme.text - : Theme.of(context).colorScheme.title, + ] else ...[ + AnimatedContainer( + padding: const EdgeInsets.all(4), + duration: DesignConfig.lowAnimationDuration, + child: Icon( + isSelected ? selectedIcon : unselectedIcon, + size: 32, + color: DesignConfig.isDark + ? Theme.of(context).colorScheme.text + : Theme.of(context).colorScheme.title, + ), ), - ), - DidvanText( - title, - style: Theme.of(context).textTheme.bodySmall, - color: Theme.of(context).colorScheme.title, - ), + if (!isHomeButton) + DidvanText( + title, + style: Theme.of(context).textTheme.bodySmall, + color: Theme.of(context).colorScheme.title, + ), + ], const Spacer(), ], ), diff --git a/lib/views/widgets/didvan/bnb_backup.dart b/lib/views/widgets/didvan/bnb_backup.dart new file mode 100644 index 0000000..0535022 --- /dev/null +++ b/lib/views/widgets/didvan/bnb_backup.dart @@ -0,0 +1,334 @@ +import 'package:didvan/constants/app_icons.dart'; +import 'package:flutter/material.dart'; +import 'dart:ui'; + +class DidvanBNB extends StatefulWidget { + final int currentTabIndex; + final void Function(int index) onTabChanged; + + const DidvanBNB({ + Key? key, + required this.currentTabIndex, + required this.onTabChanged, + }) : super(key: key); + + @override + State createState() => _DidvanBNBState(); +} + +class _DidvanBNBState extends State with TickerProviderStateMixin { + late int _activeIndex; + late AnimationController _blobController; + late Animation _blobAnim; + double _dragProgress = 0.0; // 0..1 between from->to + int _dragFrom = 0; + int _dragTo = 0; + bool _isDragging = false; + final GlobalKey _rowKey = GlobalKey(); + + @override + void initState() { + super.initState(); + _activeIndex = widget.currentTabIndex; + _blobController = AnimationController( + duration: const Duration(milliseconds: 450), + vsync: this, + ); + _blobAnim = CurvedAnimation(parent: _blobController, curve: Curves.easeOutCubic); + } + + @override + void didUpdateWidget(covariant DidvanBNB oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.currentTabIndex != _activeIndex) { + _animateTo(widget.currentTabIndex); + } + } + + void _animateTo(int newIndex) { + setState(() { + _dragFrom = _activeIndex; + _dragTo = newIndex; + _activeIndex = newIndex; + _dragProgress = 0; + _isDragging = false; + }); + _blobController.forward(from: 0); + } + + void _handleTap(int index) { + if (index == _activeIndex) return; + widget.onTabChanged(index); + } + + void _startDrag(DragStartDetails d) { + final box = _rowKey.currentContext?.findRenderObject() as RenderBox?; + if (box == null) return; + final local = box.globalToLocal(d.globalPosition); + final width = box.size.width; + final section = width / 4; // 4 items + _dragFrom = _activeIndex; + _dragTo = _activeIndex; + _dragProgress = 0; + _isDragging = true; + final pointerIndex = (local.dx / section).clamp(0, 3).floor(); + if (pointerIndex != _activeIndex) { + _dragTo = pointerIndex; + } + setState(() {}); + } + + void _updateDrag(DragUpdateDetails d) { + if (!_isDragging) return; + final box = _rowKey.currentContext?.findRenderObject() as RenderBox?; + if (box == null) return; + final width = box.size.width; + final local = box.globalToLocal(d.globalPosition); + final section = width / 4; + final pointerIndex = (local.dx / section).clamp(0, 3).floor(); + if (pointerIndex != _dragTo) { + _dragFrom = _activeIndex; + _dragTo = pointerIndex; + } + // progress relative to dragFrom->dragTo centers + final fromCenter = (_dragFrom + 0.5) * section; + final toCenter = (_dragTo + 0.5) * section; + final total = (toCenter - fromCenter); + _dragProgress = total.abs() < 2 ? 0 : ((local.dx - fromCenter) / (total)).clamp(0.0, 1.0); + setState(() {}); + } + + void _endDrag(DragEndDetails d) { + if (!_isDragging) return; + _isDragging = false; + // decide final index + final threshold = 0.5; + final target = _dragProgress > threshold ? _dragTo : _dragFrom; + if (target != _activeIndex) { + widget.onTabChanged(target); + } else { + setState(() {}); + } + } + + @override + void dispose() { + _blobController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final isDark = Theme.of(context).brightness == Brightness.dark; + return Positioned( + bottom: 12, + left: 0, + right: 0, + child: GestureDetector( + onHorizontalDragStart: _startDrag, + onHorizontalDragUpdate: _updateDrag, + onHorizontalDragEnd: _endDrag, + child: SizedBox( + height: 90, + child: Stack( + alignment: Alignment.center, + children: [ + // Liquid blob painter behind icons + LayoutBuilder( + builder: (ctx, constraints) { + final w = constraints.maxWidth; + final section = w / 4; + final fromCenter = (_dragFrom + 0.5) * section; + final toCenter = (_dragTo + 0.5) * section; + final t = _isDragging ? _dragProgress : _blobAnim.value; + final center = fromCenter + (toCenter - fromCenter) * t; + return CustomPaint( + size: Size(w, 70), + painter: _LiquidBlobPainter( + progress: t, + from: fromCenter, + to: toCenter, + center: center, + color: (isDark ? Colors.blueAccent : Colors.deepPurpleAccent).withOpacity(0.18), + highlight: (isDark ? Colors.blueAccent : Colors.deepPurpleAccent).withOpacity(0.35), + ), + ); + }, + ), + // Icons row + Align( + alignment: Alignment.center, + child: SizedBox( + height: 70, + child: Row( + key: _rowKey, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _IconItem( + index: 0, + active: _activeIndex == 0, + iconActive: DidvanIcons.house_solid, + iconInactive: DidvanIcons.house_light, + title: 'خانه', + onTap: () => _handleTap(0), + dragTarget: _dragTo, + dragProgress: _dragProgress, + isDragging: _isDragging, + ), + _IconItem( + index: 1, + active: _activeIndex == 1, + iconActive: DidvanIcons.category_solid, + iconInactive: DidvanIcons.category_light, + title: 'دسته‌بندی', + onTap: () => _handleTap(1), + dragTarget: _dragTo, + dragProgress: _dragProgress, + isDragging: _isDragging, + ), + _IconItem( + index: 3, + active: _activeIndex == 3, + iconActive: DidvanIcons.ai_solid, + iconInactive: DidvanIcons.ai_regular, + title: 'هوشان', + onTap: () => _handleTap(3), + dragTarget: _dragTo, + dragProgress: _dragProgress, + isDragging: _isDragging, + ), + _IconItem( + index: 2, + active: _activeIndex == 2, + iconActive: DidvanIcons.stats__solid, + iconInactive: DidvanIcons.stats__light, + title: 'آمار و داده', + onTap: () => _handleTap(2), + dragTarget: _dragTo, + dragProgress: _dragProgress, + isDragging: _isDragging, + ), + ], + ), + ), + ), + ], + ), + ), + ), + ); + } +} + +class _LiquidBlobPainter extends CustomPainter { + final double progress; // 0..1 + final double from; + final double to; + final double center; + final Color color; + final Color highlight; + _LiquidBlobPainter({ + required this.progress, + required this.from, + required this.to, + required this.center, + required this.color, + required this.highlight, + }); + @override + void paint(Canvas canvas, Size size) { + // Single capsule shape that stretches between from & interpolated center. + final baseY = size.height / 2; + final lerp = center; + final start = from < lerp ? from : lerp; + final end = from < lerp ? lerp : from; + final radius = 26.0; + final rect = Rect.fromLTRB(start - radius, baseY - radius, end + radius, baseY + radius); + final rrect = RRect.fromRectAndRadius(rect, Radius.circular(radius)); + final paint = Paint() + ..shader = LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + color.withOpacity(0.9), + color.withOpacity(0.4), + ], + ).createShader(rect); + // Draw blurred base using saveLayer for slight glow + canvas.saveLayer(rect.inflate(20), Paint()); + canvas.drawRRect(rrect, paint); + final glow = Paint() + ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 20) + ..color = highlight.withOpacity(0.5); + canvas.drawCircle(Offset(lerp, baseY), 14 + 6 * progress, glow); + canvas.restore(); + } + @override + bool shouldRepaint(covariant _LiquidBlobPainter old) => + old.progress != progress || old.from != from || old.to != to || old.center != center || old.color != color; +} + +class _IconItem extends StatelessWidget { + final int index; + final bool active; + final IconData iconActive; + final IconData iconInactive; + final String title; + final VoidCallback onTap; + final int dragTarget; + final double dragProgress; + final bool isDragging; + const _IconItem({ + required this.index, + required this.active, + required this.iconActive, + required this.iconInactive, + required this.title, + required this.onTap, + required this.dragTarget, + required this.dragProgress, + required this.isDragging, + }); + @override + Widget build(BuildContext context) { + final scheme = Theme.of(context).colorScheme; + final isDark = scheme.brightness == Brightness.dark; + final base = scheme.onSurface; // fallback since title extension not imported here + final activeColor = scheme.primary; + return GestureDetector( + onTap: onTap, + behavior: HitTestBehavior.translucent, + child: AnimatedContainer( + duration: const Duration(milliseconds: 300), + curve: Curves.easeOutCubic, + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + AnimatedScale( + duration: const Duration(milliseconds: 400), + curve: Curves.easeOutBack, + scale: active ? 1.15 : 1.0, + child: Icon( + active ? iconActive : iconInactive, + size: 26, + color: active ? activeColor : base.withOpacity(isDark ? 0.8 : 0.65), + ), + ), + const SizedBox(height: 2), + AnimatedDefaultTextStyle( + duration: const Duration(milliseconds: 300), + curve: Curves.easeOut, + style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontSize: 11, + fontWeight: active ? FontWeight.w700 : FontWeight.w500, + color: active ? activeColor : base.withOpacity(0.6), + ), + child: Text(title, maxLines: 1, overflow: TextOverflow.fade), + ), + ], + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/views/widgets/floating_navigation_bar.dart b/lib/views/widgets/floating_navigation_bar.dart index c7e97c1..b348212 100644 --- a/lib/views/widgets/floating_navigation_bar.dart +++ b/lib/views/widgets/floating_navigation_bar.dart @@ -101,7 +101,10 @@ class _FloatingNavigationBarState extends State { height: 48, decoration: BoxDecoration( color: Theme.of(context).colorScheme.navigation, - borderRadius: BorderRadius.circular(24), + borderRadius: const BorderRadius.only( + bottomLeft: Radius.circular(24), + bottomRight: Radius.circular(24), + ), border: DesignConfig.isDark ? Border.all( color: Theme.of(context).colorScheme.cardBorder, @@ -135,26 +138,28 @@ class _FloatingNavigationBarState extends State { ), ), const Spacer(), - SizedBox( - width: 60, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - DidvanIconButton( - gestureSize: 32, - onPressed: () => Navigator.of(context).pushNamed( - Routes.mentions, - arguments: { - 'id': widget.item.id, - 'type': widget.isRadar ? 'radar' : 'news', - 'title': widget.item.title, - }, - ), - icon: DidvanIcons.mention_icon, - ), - ], + DidvanIconButton( + gestureSize: 32, + onPressed: () => Navigator.of(context).pushNamed( + Routes.mentions, + arguments: { + 'id': widget.item.id, + 'type': widget.isRadar ? 'radar' : 'news', + 'title': widget.item.title, + }, ), + icon: DidvanIcons.mention_icon, ), + const Spacer(), + DidvanIconButton( + gestureSize: 32, + onPressed: () => Navigator.of(context).pushNamedAndRemoveUntil( + Routes.home, + (route) => false, + ), + icon: DidvanIcons.house_regular, + ), + const Spacer(), BookmarkButton( itemId: widget.item.id, type: widget.isRadar ? 'radar' : 'news', @@ -171,6 +176,7 @@ class _FloatingNavigationBarState extends State { }, gestureSize: 32, ), + const Spacer(), SizedBox( width: 60, child: Row( @@ -197,6 +203,7 @@ class _FloatingNavigationBarState extends State { ], ), ), + const Spacer(), DidvanIconButton( gestureSize: 32, onPressed: diff --git a/lib/views/widgets/overview/podcast.dart b/lib/views/widgets/overview/podcast.dart index 9b1ff6a..46d8096 100644 --- a/lib/views/widgets/overview/podcast.dart +++ b/lib/views/widgets/overview/podcast.dart @@ -5,7 +5,6 @@ import 'package:didvan/models/overview_data.dart'; import 'package:didvan/models/requests/studio.dart'; import 'package:didvan/providers/media.dart'; import 'package:didvan/routes/routes.dart'; -import 'package:didvan/views/podcasts/studio_details/studio_details_state.dart'; import 'package:didvan/views/widgets/bookmark_button.dart'; import 'package:didvan/views/widgets/duration_widget.dart'; import 'package:didvan/views/widgets/didvan/card.dart'; diff --git a/lib/views/widgets/search_field.dart b/lib/views/widgets/search_field.dart index c9849f0..5d511ab 100644 --- a/lib/views/widgets/search_field.dart +++ b/lib/views/widgets/search_field.dart @@ -1,7 +1,6 @@ import 'package:didvan/config/theme_data.dart'; -import 'package:didvan/constants/app_icons.dart'; -import 'package:didvan/views/widgets/didvan/icon_button.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; class SearchField extends StatefulWidget { final String title; @@ -11,6 +10,8 @@ class SearchField extends StatefulWidget { final VoidCallback? onFilterButtonPressed; final VoidCallback? onGoBack; final String? value; + final String? extraIconPath; + final VoidCallback? onExtraIconPressed; const SearchField({ Key? key, @@ -21,6 +22,8 @@ class SearchField extends StatefulWidget { this.isFiltered, this.onGoBack, this.value, + this.extraIconPath, + this.onExtraIconPressed, }) : super(key: key); @override @@ -41,13 +44,14 @@ class _SearchFieldState extends State { @override Widget build(BuildContext context) { return SizedBox( - height: 40, + height: 47, child: Row( children: [ Expanded( child: Container( decoration: BoxDecoration( - color: _fillColor(), + color: const Color.fromARGB(255, 235, 235, 235), + borderRadius: BorderRadius.circular(40), ), child: TextFormField( initialValue: widget.value, @@ -68,22 +72,18 @@ class _SearchFieldState extends State { child: Row( mainAxisSize: MainAxisSize.min, children: [ - Container( - margin: const EdgeInsets.only(left: 4), - height: 24, - width: 1, - color: Theme.of(context).colorScheme.border, - ), Stack( children: [ - DidvanIconButton( - onPressed: - widget.onFilterButtonPressed!, - icon: widget.isFiltered! - ? DidvanIcons.filter_solid - : DidvanIcons.filter_regular, - size: 24, - gestureSize: 24, + GestureDetector( + onTap: widget.onFilterButtonPressed!, + child: Container( + width: 27, + height: 27, + padding: const EdgeInsets.all(4), + child: SvgPicture.asset( + "lib/assets/icons/search sort.svg", + ), + ), ), if (widget.isFiltered!) Positioned( @@ -108,7 +108,7 @@ class _SearchFieldState extends State { : null, focusedBorder: OutlineInputBorder( borderRadius: const BorderRadius.all( - Radius.circular(4), + Radius.circular(35), ), borderSide: BorderSide( color: Theme.of(context).colorScheme.primary, @@ -116,17 +116,21 @@ class _SearchFieldState extends State { ), prefixIcon: GestureDetector( onTap: widget.onGoBack, - child: Icon( - widget.onGoBack == null - ? DidvanIcons.search_regular - : DidvanIcons.back_light, - color: Theme.of(context).colorScheme.text, + child: Padding( + padding: const EdgeInsets.all(11.0), + child: SvgPicture.asset( + widget.onGoBack == null + ? 'lib/assets/icons/search.svg' + : 'lib/assets/icons/search.svg', + width: 23, + height: 23, + ), ), ), prefixIconColor: Theme.of(context).colorScheme.inputText, enabledBorder: OutlineInputBorder( borderRadius: const BorderRadius.all( - Radius.circular(4), + Radius.circular(20), ), borderSide: BorderSide( color: Theme.of(context).colorScheme.border, @@ -138,25 +142,46 @@ class _SearchFieldState extends State { right: 12, ), border: InputBorder.none, - hintText: 'جستجو در ${widget.title}', - hintStyle: TextStyle( - color: Theme.of(context).colorScheme.disabledText, + hintText: 'جست‌وجو در ${widget.title}', + hintStyle: const TextStyle( + color: Color.fromARGB(255, 122, 122, 122), + fontSize: 13, ), ), ), ), ), + if (widget.extraIconPath != null && widget.onExtraIconPressed != null) ...[ + const SizedBox(width: 8), + GestureDetector( + onTap: widget.onExtraIconPressed, + child: Container( + width: 47, + height: 47, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.primary, + shape: BoxShape.circle, + ), + child: Center( + child: SvgPicture.asset( + "lib/assets/icons/live ai.svg", + width: 24, + height: 24, + colorFilter: const ColorFilter.mode( + Colors.white, + BlendMode.srcIn, + ), + ), + ), + ), + ), + ], ], ), ); } - Color _fillColor() { - if (widget.focusNode.hasFocus) { - return Theme.of(context).colorScheme.surface; - } - return Theme.of(context).colorScheme.surface; - } + @override void dispose() { diff --git a/lib/views/widgets/text_divider.dart b/lib/views/widgets/text_divider.dart new file mode 100644 index 0000000..dce93e9 --- /dev/null +++ b/lib/views/widgets/text_divider.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; + +class TextDivider extends StatelessWidget { + final String text; + final Color? textColor; + final Color? lineColor; + final TextStyle? textStyle; + final double? lineThickness; + final EdgeInsets? padding; + + const TextDivider({ + Key? key, + required this.text, + this.textColor, + this.lineColor, + this.textStyle, + this.lineThickness, + this.padding, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + padding: padding ?? const EdgeInsets.symmetric(horizontal: 16, vertical: 16), + child: Row( + children: [ + Expanded( + child: Divider( + color: lineColor ?? Theme.of(context).dividerColor, + thickness: lineThickness ?? 1.0, + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + text, + style: textStyle ?? Theme.of(context).textTheme.bodyMedium?.copyWith( + color: textColor ?? Theme.of(context).colorScheme.onSurface, + fontWeight: FontWeight.bold, + ), + ), + ), + Expanded( + child: Divider( + color: lineColor ?? Theme.of(context).dividerColor, + thickness: lineThickness ?? 1.0, + ), + ), + ], + ), + ); + } +} \ No newline at end of file diff --git a/macos/Flutter/ephemeral/Flutter-Generated.xcconfig b/macos/Flutter/ephemeral/Flutter-Generated.xcconfig index 727f32a..ae25c99 100644 --- a/macos/Flutter/ephemeral/Flutter-Generated.xcconfig +++ b/macos/Flutter/ephemeral/Flutter-Generated.xcconfig @@ -1,6 +1,6 @@ // This is a generated file; do not edit or check into version control. -FLUTTER_ROOT=/Users/arytan/Desktop/Dev/Sdks/flutter -FLUTTER_APPLICATION_PATH=/Users/arytan/Desktop/Flutter Projects/didvan-app +FLUTTER_ROOT=C:\Users\UI-UX\AppData\Local\flutter +FLUTTER_APPLICATION_PATH=C:\Users\UI-UX\Desktop\projects\didvan-app COCOAPODS_PARALLEL_CODE_SIGN=true FLUTTER_BUILD_DIR=build FLUTTER_BUILD_NAME=4.0.1 diff --git a/macos/Flutter/ephemeral/flutter_export_environment.sh b/macos/Flutter/ephemeral/flutter_export_environment.sh index 73d3d77..9e7da27 100644 --- a/macos/Flutter/ephemeral/flutter_export_environment.sh +++ b/macos/Flutter/ephemeral/flutter_export_environment.sh @@ -1,7 +1,7 @@ #!/bin/sh # This is a generated file; do not edit or check into version control. -export "FLUTTER_ROOT=/Users/arytan/Desktop/Dev/Sdks/flutter" -export "FLUTTER_APPLICATION_PATH=/Users/arytan/Desktop/Flutter Projects/didvan-app" +export "FLUTTER_ROOT=C:\Users\UI-UX\AppData\Local\flutter" +export "FLUTTER_APPLICATION_PATH=C:\Users\UI-UX\Desktop\projects\didvan-app" export "COCOAPODS_PARALLEL_CODE_SIGN=true" export "FLUTTER_BUILD_DIR=build" export "FLUTTER_BUILD_NAME=4.0.1" diff --git a/pubspec.yaml b/pubspec.yaml index 6975f6a..306afe3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -126,7 +126,6 @@ dev_dependencies: # package. See that file for information about deactivating specific lint # rules and activating additional ones. flutter_lints: ^2.0.1 - # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec @@ -191,6 +190,21 @@ flutter: - family: Dicon fonts: - asset: lib/assets/icons/Dicon.ttf + - family: IranYekan + fonts: + - asset: lib/assets/fonts/IRANYEKANREGULAR.TTF + - asset: lib/assets/fonts/IRANYEKANTHIN.TTF + weight: 100 + - asset: lib/assets/fonts/IRANYEKANLIGHT.TTF + weight: 300 + - asset: lib/assets/fonts/IRANYEKANMEDIUM.TTF + weight: 500 + - asset: lib/assets/fonts/IRANYEKANBOLD.TTF + weight: 700 + - asset: lib/assets/fonts/IRANYEKANEXTRABOLD.TTF + weight: 800 + - asset: lib/assets/fonts/IRANYEKANBLACK.TTF + weight: 900 # fonts: # - family: Schyler # fonts: