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: