diff --git a/lib/assets/icons/houshanNav/streamline-flex_ai-scanner-robot-remix.svg b/lib/assets/icons/houshanNav/streamline-flex_ai-scanner-robot-remix.svg
new file mode 100644
index 0000000..6457772
--- /dev/null
+++ b/lib/assets/icons/houshanNav/streamline-flex_ai-scanner-robot-remix.svg
@@ -0,0 +1,10 @@
+
diff --git a/lib/assets/icons/houshanNav/streamline-flex_ai-scanner-robot.svg b/lib/assets/icons/houshanNav/streamline-flex_ai-scanner-robot.svg
new file mode 100644
index 0000000..ae6a189
--- /dev/null
+++ b/lib/assets/icons/houshanNav/streamline-flex_ai-scanner-robot.svg
@@ -0,0 +1,3 @@
+
diff --git a/lib/main.dart b/lib/main.dart
index 0d6b045..7f4effe 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -18,6 +18,7 @@ import 'package:didvan/services/media/media.dart';
import 'package:didvan/services/notification/firebase_api.dart';
import 'package:didvan/services/notification/notification_service.dart';
import 'package:didvan/utils/my_custom_scroll_behavior.dart';
+import 'package:didvan/views/ai/ai_chat_state.dart';
import 'package:didvan/views/ai/ai_state.dart';
import 'package:didvan/views/ai/bot_assistants_state.dart';
import 'package:didvan/views/ai/history_ai_chat_state.dart';
@@ -35,24 +36,6 @@ import 'package:sentry_flutter/sentry_flutter.dart';
final GlobalKey navigatorKey = GlobalKey();
-// @pragma('vm:entry-point')
-// Future _initPushNotification(RemoteMessage message) async {
-// if (!kIsWeb) {
-// await NotificationService.startListeningNotificationEvents();
-// }
-// await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
-// // if (kDebugMode) {
-// print("background: ${NotificationData.fromJson(message.data).toJson()}");
-// // }
-// try {
-// NotificationService.showFirebaseNotification(message);
-// } catch (e) {
-// // if (kDebugMode) {
-// print(e);
-// // }
-// }
-// }
-
@pragma('vm:entry-point')
Future _backgroundCallbackHomeWidget(Uri? uri) async {
await HomeWidget.saveWidgetData("uri", uri!.host);
@@ -76,9 +59,9 @@ void main() async {
if (Platform.isAndroid) {
await FlutterDownloader.initialize(
debug:
- true, // optional: set to false to disable printing logs to console (default: true)
+ true,
ignoreSsl:
- true // option: set to false to disable working with http links (default: false)
+ true
);
}
} catch (e) {
@@ -86,7 +69,6 @@ void main() async {
}
}
- // FirebaseMessaging.onBackgroundMessage(_initPushNotification);
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform);
await FirebaseApi().initNotification();
@@ -98,11 +80,7 @@ void main() async {
(options) {
options.dsn =
'https://a4cfcaa7d67471240d295c25c968d91d@o4508585857384448.ingest.de.sentry.io/4508585886548048';
- // Set tracesSampleRate to 1.0 to capture 100% of transactions for tracing.
- // We recommend adjusting this value in production.
options.tracesSampleRate = 1.0;
- // The sampling rate for profiling is relative to tracesSampleRate
- // Setting to 1.0 will profile 100% of sampled transactions:
options.profilesSampleRate = 1.0;
},
appRunner: () => runApp(const Didvan()),
@@ -124,19 +102,13 @@ class _DidvanState extends State with WidgetsBindingObserver {
@override
void initState() {
- // if (!kIsWeb) {
- // NotificationService.startListeningNotificationEvents();
- // }
WidgetsBinding.instance.addObserver(this);
- // NotificationService.startListeningNotificationEvents();
-
super.initState();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
- // MediaService.audioPlayer.dispose();
if (MediaService.currentPodcast != null) {
MediaService.audioPlayer.dispose();
}
@@ -151,7 +123,7 @@ class _DidvanState extends State with WidgetsBindingObserver {
if (state == AppLifecycleState.resumed) {
var r = await HomeWidget.getWidgetData("cRoute", defaultValue: '');
if (r!.toString() != Routes.splash) {
- await HomeWidgetRepository.decideWhereToGo();
+ await HomeWidgetRepository.decideWhereToGo();
NotificationMessage? data = HomeWidgetRepository.data;
@@ -188,12 +160,12 @@ class _DidvanState extends State with WidgetsBindingObserver {
ChangeNotifierProvider(
create: (context) => AiState(),
),
+ ChangeNotifierProvider(
+ create: (context) => AiChatState(),
+ ),
ChangeNotifierProvider(
create: (context) => BotAssistantsState(),
),
- // ChangeNotifierProvider(
- // create: (context) => StoryViewerState(),
- // ),
],
child: Consumer(
builder: (context, themeProvider, child) => Container(
@@ -223,7 +195,6 @@ class _DidvanState extends State with WidgetsBindingObserver {
onGenerateRoute: (settings) =>
RouteGenerator.generateRoute(settings),
builder: BotToastInit(),
- //1. call BotToastInit
navigatorObservers: [BotToastNavigatorObserver()],
initialRoute: "/",
localizationsDelegates: const [
@@ -240,4 +211,4 @@ class _DidvanState extends State with WidgetsBindingObserver {
),
);
}
-}
+}
\ No newline at end of file
diff --git a/lib/models/story_model.dart b/lib/models/story_model.dart
index 6d747a9..03c9f36 100644
--- a/lib/models/story_model.dart
+++ b/lib/models/story_model.dart
@@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
enum MediaType { image, video, gif }
-// Represents a single story item (image, gif, or video)
class StoryItem {
final int id;
final String url;
@@ -38,8 +37,6 @@ class StoryItem {
id: json['id'],
url: json['mediaUrl'],
media: mediaType,
- // API doesn't provide duration for images/gifs, so we use a default.
- // For videos, the player controller will determine the duration.
duration: const Duration(seconds: 10),
);
}
@@ -57,9 +54,8 @@ class User {
});
}
-// This class will wrap the API response and fit it into the UI's expected structure.
class UserStories {
- final int id; // The main story ID from the API
+ final int id;
final User user;
final List stories;
@@ -76,14 +72,13 @@ class UserStories {
return UserStories(
id: json['id'],
user: User(
- name: json['title'], // Using title directly from the API
+ name: json['title'],
profileImageUrl:
- _mapCategoryToIcon(json['category']), // Mapping category to an icon
+ _mapCategoryToIcon(json['category']),
createdAt: json['createdAt'],
),
stories: items.map((item) {
final storyItem = StoryItem.fromJson(item);
- // Check if this story item has been viewed.
if (completedIds.contains(storyItem.id)) {
storyItem.isViewed.value = true;
}
diff --git a/lib/services/ai/ai_api_service.dart b/lib/services/ai/ai_api_service.dart
index a1631f4..0bd80bb 100644
--- a/lib/services/ai/ai_api_service.dart
+++ b/lib/services/ai/ai_api_service.dart
@@ -1,7 +1,6 @@
// ignore_for_file: depend_on_referenced_packages, avoid_web_libraries_in_flutter
import 'dart:async';
-import 'dart:convert';
import 'package:didvan/models/ai/files_model.dart';
import 'package:didvan/services/storage/storage.dart';
diff --git a/lib/services/network/request_helper.dart b/lib/services/network/request_helper.dart
index 6f9ffda..1f35e4c 100644
--- a/lib/services/network/request_helper.dart
+++ b/lib/services/network/request_helper.dart
@@ -20,7 +20,7 @@ class RequestHelper {
static const String _baseHomeUrl = '$baseUrl/home';
static const String _baseNewStats = '$baseUrl/home/statistic';
static const String _baseNewStatsSearch = '$baseUrl/home/statistic/search';
- static const String checkHasPassword = '$_baseUserUrl/checkHasPassword';
+ static const String checkHasPassword = '$_baseUserUrl/checkHasPassword';
static const String mainPageContent = _baseHomeUrl;
static String searchAll({
diff --git a/lib/utils/action_sheet.dart b/lib/utils/action_sheet.dart
index 1425866..580bc5e 100644
--- a/lib/utils/action_sheet.dart
+++ b/lib/utils/action_sheet.dart
@@ -206,7 +206,9 @@ class ActionSheetUtils {
data.backgroundColor ?? Theme.of(context).colorScheme.surface,
),
width: mediaQueryData.size.width * 0.8,
- padding: const EdgeInsets.all(24.0),
+ // BEGIN: EDIT THIS LINE
+ padding: const EdgeInsets.fromLTRB(24, 16, 24, 24), // پدینگ بالا از 24 به 16 تغییر کرد
+ // END: EDIT THIS LINE
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
@@ -397,8 +399,8 @@ class ActionSheetUtils {
),
),
Positioned(
- right: 24,
- top: 24,
+ right: 16,
+ top: 0,
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
@@ -446,4 +448,4 @@ class ActionSheetUtils {
DesignConfig.updateSystemUiOverlayStyle();
Navigator.of(context).pop();
}
-}
+}
\ No newline at end of file
diff --git a/lib/views/ai/ai.dart b/lib/views/ai/ai.dart
index c8dd299..8e02014 100644
--- a/lib/views/ai/ai.dart
+++ b/lib/views/ai/ai.dart
@@ -1,375 +1,309 @@
-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/models/ai/ai_chat_args.dart';
-import 'package:didvan/routes/routes.dart';
-import 'package:didvan/utils/action_sheet.dart';
-import 'package:didvan/views/ai/ai_state.dart';
-import 'package:didvan/views/ai/history_ai_chat_state.dart';
-import 'package:didvan/views/ai/tool_screen.dart';
-import 'package:didvan/views/ai/widgets/message_bar_btn.dart';
-import 'package:didvan/views/widgets/didvan/text.dart';
-import 'package:didvan/views/widgets/shimmer_placeholder.dart';
-import 'package:didvan/views/widgets/skeleton_image.dart';
-import 'package:didvan/views/widgets/state_handlers/empty_connection.dart';
-import 'package:didvan/views/widgets/state_handlers/empty_state.dart';
-import 'package:flutter/material.dart';
-import 'package:provider/provider.dart';
+ // lib/views/ai/ai.dart
-class Ai extends StatefulWidget {
- const Ai({Key? key}) : super(key: key);
+ 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/models/ai/ai_chat_args.dart';
+ import 'package:didvan/views/ai/ai_state.dart';
+ import 'package:didvan/views/ai/history_ai_chat_state.dart';
+ import 'package:didvan/views/ai/tool_screen.dart';
+ import 'package:didvan/views/ai/widgets/message_bar_btn.dart';
+ import 'package:didvan/views/widgets/didvan/text.dart';
+ import 'package:didvan/views/widgets/shimmer_placeholder.dart';
+ import 'package:didvan/views/widgets/state_handlers/empty_connection.dart';
+ import 'package:didvan/views/widgets/state_handlers/empty_state.dart';
+ import 'package:flutter/material.dart';
+ import 'package:provider/provider.dart';
- @override
- // ignore: library_private_types_in_public_api
- _AiState createState() => _AiState();
-}
+ class Ai extends StatefulWidget {
+ const Ai({Key? key}) : super(key: key);
-class _AiState extends State {
- @override
- void initState() {
- super.initState();
- context.read().getTools();
+ @override
+ _AiState createState() => _AiState();
}
- @override
- Widget build(BuildContext context) {
- return Stack(
- children: [
- Consumer(
- builder: (BuildContext context, state, Widget? child) {
- switch (state.page) {
- case 1:
- return const ToolScreen();
- case 0:
- default:
- return Consumer(
- builder: (context, state, child) {
- if (state.bots.isEmpty) {
- return Center(
- child: Image.asset(
- Assets.loadingAnimation,
- width: 60,
- height: 60,
- ),
- );
- }
- final bot = state.bot!;
- return Column(
- mainAxisAlignment: MainAxisAlignment.end,
- children: [
- Expanded(
- child: SingleChildScrollView(
- child: Padding(
- padding:
- const EdgeInsets.only(bottom: 24, top: 70),
- child: Column(
- children: [
- Consumer(
- builder: (BuildContext context,
- AiState state, Widget? child) {
- final tools = state.tools;
- if (tools != null && tools.isEmpty) {
- return EmptyState(
- asset: Assets.emptyResult,
- title: 'لیست خالی است',
- );
- }
- if (state.loading) {
- return toolsPlaceHolder();
- }
- if (tools == null) {
- return Padding(
- padding: EdgeInsets.only(
- top: MediaQuery.sizeOf(context)
- .height *
- 0.1),
- child: Center(
- child: EmptyConnection(
- onRetry: () {
- context
- .read()
- .getTools();
- },
- ),
- ),
- );
- }
+ class _AiState extends State {
+ @override
+ void initState() {
+ super.initState();
+ context.read().getTools();
+ context.read().getBots();
+ }
- return const SizedBox();
- },
- )
- ],
+ @override
+ Widget build(BuildContext context) {
+ return Stack(
+ children: [
+ Consumer(
+ builder: (BuildContext context, state, Widget? child) {
+ switch (state.page) {
+ case 1:
+ return const ToolScreen();
+ case 0:
+ default:
+ return Consumer(
+ builder: (context, historyState, child) {
+ if (historyState.bots.isEmpty) {
+ return Center(
+ child: Image.asset(
+ Assets.loadingAnimation,
+ width: 60,
+ height: 60,
+ ),
+ );
+ }
+ final bot = historyState.bot!;
+ return Column(
+ mainAxisAlignment: MainAxisAlignment.end,
+ children: [
+ Expanded(
+ child: SingleChildScrollView(
+ child: Padding(
+ padding:
+ const EdgeInsets.only(bottom: 24, top: 70),
+ child: Column(
+ children: [
+ Consumer(
+ builder: (BuildContext context,
+ AiState aiState, Widget? child) {
+ final tools = aiState.tools;
+ if (tools != null && tools.isEmpty) {
+ return EmptyState(
+ asset: Assets.emptyResult,
+ title: 'لیست خالی است',
+ );
+ }
+ if (aiState.loading) {
+ return toolsPlaceHolder();
+ }
+ if (tools == null) {
+ return Padding(
+ padding: EdgeInsets.only(
+ top: MediaQuery.sizeOf(context)
+ .height *
+ 0.1),
+ child: Center(
+ child: EmptyConnection(
+ onRetry: () {
+ context
+ .read()
+ .getTools();
+ },
+ ),
+ ),
+ );
+ }
+
+ return const SizedBox();
+ },
+ )
+ ],
+ ),
),
),
),
- ),
- Padding(
- padding: const EdgeInsets.fromLTRB(20, 0, 20, 12),
- child: Column(
- mainAxisSize: MainAxisSize.min,
- crossAxisAlignment: CrossAxisAlignment.end,
- children: [
- InkWell(
- onTap: () {
- final historyState =
- context.read();
- if (historyState.bots.isEmpty) {
- historyState.getBots();
- }
- ActionSheetUtils(context)
- .botsDialogSelect(context: context);
- },
- borderRadius: BorderRadius.circular(12),
- child: const SizedBox(),
- // Padding(
- // padding: const EdgeInsets.symmetric(
- // vertical: 8.0, horizontal: 12.0),
- // child: Row(
- // mainAxisSize: MainAxisSize.min,
- // crossAxisAlignment:
- // CrossAxisAlignment.center,
- // mainAxisAlignment: MainAxisAlignment.start,
- // children: [
- // Icon(DidvanIcons.angle_down_light,
- // size: 16,
- // color: Theme.of(context)
- // .colorScheme
- // .title),
- // const SizedBox(
- // width: 8,
- // ),
- // DidvanText(
- // bot.name.toString(),
- // color: Theme.of(context)
- // .colorScheme
- // .title,
- // style: const TextStyle(
- // fontWeight: FontWeight.bold),
- // ),
- // const SizedBox(
- // width: 12,
- // ),
- // SkeletonImage(
- // width: 28,
- // height: 28,
- // imageUrl: bot.image.toString(),
- // borderRadius:
- // BorderRadius.circular(360),
- // ),
- // ],
- // ),
- // ),
- ),
- InkWell(
- onTap: () => Navigator.of(context)
- .pushNamed(Routes.aiChat,
- arguments: AiChatArgs(
- bot: bot,
- )),
- child: Column(
- children: [
- Row(
- children: [
- Expanded(
- child: Container(
- decoration: BoxDecoration(
- color: Theme.of(context)
- .colorScheme
- .surface,
- border: Border.all(
- color: const Color.fromARGB(255, 0, 126, 167),width: 1.5),
- borderRadius: BorderRadius.circular(50)),
- child: Row(
- children: [
- Expanded(
- child: Padding(
- padding:
- const EdgeInsets
- .symmetric(
- horizontal: 8.0,
- ),
- child: Form(
- child: Row(
- children: [
- const MessageBarBtn(
- enable: true,
- icon: DidvanIcons
- .mic_regular),
- const SizedBox(
- width: 8,
- ),
- Expanded(
- child:
- TextFormField(
- textInputAction:
- TextInputAction
- .newline,
- style: Theme.of(
- context)
- .textTheme
- .bodyMedium,
- minLines: 1,
- enabled:
- false,
- decoration:
- InputDecoration(
- border:
- InputBorder
- .none,
- hintText:
- 'بنویسید یا پیام صوتی بگذارید...',
- hintStyle: Theme.of(
+ Padding(
+ padding: const EdgeInsets.fromLTRB(20, 0, 20, 12),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.end,
+ children: [
+ InkWell(
+ onTap: () =>
+ context.read().startChat(
+ AiChatArgs(
+ bot: bot,
+ isTool: historyState.bots)),
+ child: Column(
+ children: [
+ Row(
+ children: [
+ Expanded(
+ child: Container(
+ decoration: BoxDecoration(
+ color: Theme.of(context)
+ .colorScheme
+ .surface,
+ border: Border.all(
+ color:
+ const Color.fromARGB(
+ 255, 0, 126, 167),
+ width: 1.5),
+ borderRadius:
+ BorderRadius.circular(
+ 50)),
+ child: Row(
+ children: [
+ Expanded(
+ child: Padding(
+ padding:
+ const EdgeInsets
+ .symmetric(
+ horizontal: 8.0,
+ ),
+ child: Form(
+ child: Row(
+ children: [
+ const MessageBarBtn(
+ enable: true,
+ icon: DidvanIcons
+ .mic_regular),
+ const SizedBox(
+ width: 8,
+ ),
+ Expanded(
+ child:
+ TextFormField(
+ textInputAction:
+ TextInputAction
+ .newline,
+ style: Theme.of(
context)
.textTheme
- .bodySmall!
- .copyWith(
- color:
- Theme.of(context).colorScheme.disabledText),
+ .bodyMedium,
+ minLines: 1,
+ enabled:
+ false,
+ decoration:
+ InputDecoration(
+ border:
+ InputBorder
+ .none,
+ hintText:
+ 'بنویسید یا پیام صوتی بگذارید...',
+ hintStyle: Theme.of(
+ context)
+ .textTheme
+ .bodySmall!
+ .copyWith(
+ color:
+ Theme.of(context).colorScheme.disabledText),
+ ),
),
),
- ),
- const SizedBox(
- width: 8,
- ),
- MessageBarBtn(
- click: () {
- Navigator.of(context).pushNamed(
- Routes
- .aiChat,
- arguments: AiChatArgs(
+ const SizedBox(
+ width: 8,
+ ),
+ MessageBarBtn(
+ click: () {
+ context
+ .read<
+ AiState>()
+ .startChat(
+ AiChatArgs(
bot:
bot,
attach:
- true));
- },
- enable: false,
- icon: Icons
- .add),
- ],
- ))))
- ],
+ true,
+ ));
+ },
+ enable: false,
+ icon: Icons
+ .add),
+ ],
+ ))))
+ ],
+ ),
),
),
- ),
- ],
- ),
- const Padding(
- padding:
- EdgeInsets.fromLTRB(8, 8, 8, 4),
- child: FittedBox(
- child: DidvanText(
- 'مدلهای هوش مصنوعی میتوانند اشتباه کنند، صحت اطلاعات مهم را بررسی کنید.',style: TextStyle(fontWeight: FontWeight.w600),
- ),
+ ],
),
- )
- ],
- )),
- ],
+ const Padding(
+ padding:
+ EdgeInsets.fromLTRB(8, 8, 8, 4),
+ child: FittedBox(
+ child: DidvanText(
+ 'مدلهای هوش مصنوعی میتوانند اشتباه کنند، صحت اطلاعات مهم را بررسی کنید.',
+ style: TextStyle(
+ fontWeight: FontWeight.w600),
+ ),
+ ),
+ )
+ ],
+ )),
+ ],
+ ),
),
- ),
- ],
- );
- },
- );
- }
- },
- ),
- Consumer(builder: (context, state, child) {
- if (state.bots.isEmpty) return const SizedBox();
- return Positioned(
- top: 32,
- right: 0,
- child: InkWell(
- onTap: () => Scaffold.of(context).openDrawer(),
- child: Container(
- width: 46,
- height: 46,
- decoration: BoxDecoration(
- color: Theme.of(context).colorScheme.surface,
- borderRadius: const BorderRadius.only(
- topLeft: Radius.circular(12),
- bottomLeft: Radius.circular(12)),
- boxShadow: DesignConfig.defaultShadow),
- child: Icon(
- DidvanIcons.angle_left_light,
- color: Theme.of(context).colorScheme.title,
- ),
- )),
- );
- })
- ],
- );
- }
+ ],
+ );
+ },
+ );
+ }
+ },
+ ),
+ ],
+ );
+ }
- ListView toolsPlaceHolder() {
- return ListView.builder(
- itemCount: 10,
- shrinkWrap: true,
- padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 24),
- physics: const NeverScrollableScrollPhysics(),
- itemBuilder: (context, index) {
- return Container(
- decoration: BoxDecoration(
- borderRadius: DesignConfig.lowBorderRadius,
- border: Border.all(
- color: const Color(0xffB8B8B8),
+ ListView toolsPlaceHolder() {
+ return ListView.builder(
+ itemCount: 10,
+ shrinkWrap: true,
+ padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 24),
+ physics: const NeverScrollableScrollPhysics(),
+ itemBuilder: (context, index) {
+ return Container(
+ decoration: BoxDecoration(
+ borderRadius: DesignConfig.lowBorderRadius,
+ border: Border.all(
+ color: const Color(0xffB8B8B8),
+ ),
),
- ),
- padding: const EdgeInsets.all(24),
- margin: const EdgeInsets.symmetric(vertical: 8),
- child: Row(
- children: [
- ShimmerPlaceholder(
- width: 75,
- height: 75,
- borderRadius: BorderRadius.circular(360),
- ),
- const SizedBox(
- width: 8,
- ),
- const Expanded(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- ShimmerPlaceholder(
- width: 120,
- height: 24,
- borderRadius: DesignConfig.mediumBorderRadius,
- ),
- ShimmerPlaceholder(
- width: 60,
- height: 24,
- borderRadius: DesignConfig.mediumBorderRadius,
- ),
- ],
- ),
- SizedBox(
- height: 8,
- ),
- ShimmerPlaceholder(
- width: 120,
- height: 24,
- borderRadius: DesignConfig.mediumBorderRadius,
- ),
- SizedBox(
- height: 8,
- ),
- ShimmerPlaceholder(
- width: 240,
- height: 46,
- borderRadius: DesignConfig.mediumBorderRadius,
- ),
- ],
+ padding: const EdgeInsets.all(24),
+ margin: const EdgeInsets.symmetric(vertical: 8),
+ child: Row(
+ children: [
+ ShimmerPlaceholder(
+ width: 75,
+ height: 75,
+ borderRadius: BorderRadius.circular(360),
),
- )
- ],
- ),
- );
- },
- );
- }
-}
\ No newline at end of file
+ const SizedBox(
+ width: 8,
+ ),
+ const Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ ShimmerPlaceholder(
+ width: 120,
+ height: 24,
+ borderRadius: DesignConfig.mediumBorderRadius,
+ ),
+ ShimmerPlaceholder(
+ width: 60,
+ height: 24,
+ borderRadius: DesignConfig.mediumBorderRadius,
+ ),
+ ],
+ ),
+ SizedBox(
+ height: 8,
+ ),
+ ShimmerPlaceholder(
+ width: 120,
+ height: 24,
+ borderRadius: DesignConfig.mediumBorderRadius,
+ ),
+ SizedBox(
+ height: 8,
+ ),
+ ShimmerPlaceholder(
+ width: 240,
+ height: 46,
+ borderRadius: DesignConfig.mediumBorderRadius,
+ ),
+ ],
+ ),
+ )
+ ],
+ ),
+ );
+ },
+ );
+ }
+ }
\ No newline at end of file
diff --git a/lib/views/ai/ai_chat_page.dart b/lib/views/ai/ai_chat_page.dart
index a294bed..95d40cf 100644
--- a/lib/views/ai/ai_chat_page.dart
+++ b/lib/views/ai/ai_chat_page.dart
@@ -1,12 +1,14 @@
+// lib/views/ai/ai_chat_page.dart
+
// ignore_for_file: library_private_types_in_public_api, deprecated_member_use, depend_on_referenced_packages, unnecessary_import
import 'dart:io' show Platform;
+import 'package:didvan/views/widgets/state_handlers/state_handler.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
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/ai/ai_chat_args.dart';
import 'package:didvan/models/ai/chats_model.dart';
@@ -28,7 +30,6 @@ import 'package:didvan/views/ai/widgets/audio_wave.dart';
import 'package:didvan/views/ai/widgets/hoshan_drawer.dart';
import 'package:didvan/views/widgets/didvan/didvan_markdown.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
-import 'package:didvan/views/widgets/hoshan_app_bar.dart';
import 'package:didvan/views/widgets/marquee_text.dart';
import 'package:didvan/views/widgets/skeleton_image.dart';
import 'package:didvan/views/widgets/video/chat_video_player.dart';
@@ -52,6 +53,34 @@ class _AiChatPageState extends State {
final GlobalKey scaffKey = GlobalKey();
FocusNode focusNode = FocusNode();
+ @override
+ void didUpdateWidget(covariant AiChatPage oldWidget) {
+ super.didUpdateWidget(oldWidget);
+ if (widget.args.bot.id != oldWidget.args.bot.id) {
+ final state = context.read();
+ state.clearChat();
+
+ if (widget.args.chat != null) {
+ state.chatId = widget.args.chat!.id!;
+ state.chat = widget.args.chat;
+ state.getAllMessages(state.chatId!);
+ }
+
+
+ if (widget.args.prompts != null) {
+ state.messages.add(MessageModel(
+ dateTime: DateTime.now()
+ .subtract(const Duration(minutes: 210))
+ .toIso8601String(),
+ prompts: [widget.args.prompts!]));
+
+ state.message.clear();
+ state.update();
+ state.postMessage(
+ widget.args.bot, widget.args.assistantsName != null);
+ }
+ }
+}
@override
void initState() {
final state = context.read();
@@ -59,6 +88,8 @@ class _AiChatPageState extends State {
state.chatId = widget.args.chat!.id!;
state.chat = widget.args.chat;
}
+
+
WidgetsBinding.instance.addPostFrameCallback((_) async {
if (state.chatId != null) {
state.getAllMessages(state.chatId!).then((value) => Future.delayed(
@@ -68,6 +99,7 @@ class _AiChatPageState extends State {
() => focusNode.requestFocus(),
));
} else {
+ state.appState = AppState.idle;
Future.delayed(
const Duration(
milliseconds: 100,
@@ -103,145 +135,141 @@ class _AiChatPageState extends State {
},
child: Consumer(
builder: (context, state, child) => Scaffold(
- appBar: HoshanAppBar(
- onBack: () {
- Navigator.pop(context);
- },
- withActions: false,
- ),
+ // appBar: HoshanAppBar(
+ // onBack: () {
+ // Navigator.pop(context);
+ // },
+ // withActions: false,
+ // ),
key: scaffKey,
resizeToAvoidBottomInset: true,
drawer: HoshanDrawer(
scaffKey: scaffKey,
),
- body: state.loading
- ? Center(
- child: Image.asset(
- Assets.loadingAnimation,
- width: 60,
- height: 60,
- ),
- )
- : Stack(
- children: [
- SingleChildScrollView(
- reverse: true,
- controller: state.scrollController,
- child: Column(
- children: [
- Column(
- crossAxisAlignment: CrossAxisAlignment.center,
- children: [
- const SizedBox(
- height: 24,
- ),
- SkeletonImage(
- width: 75,
- height: 75,
- imageUrl: widget.args.bot.image.toString(),
- borderRadius: BorderRadius.circular(360),
- ),
- const SizedBox(
- height: 12,
- ),
- DidvanText(
- widget.args.assistantsName ??
- widget.args.bot.name.toString(),
- fontSize: 17,
- fontWeight: FontWeight.bold,
- ),
- if (state.messages.isEmpty)
- Column(
+ body: StateHandler(
+ state: state,
+ onRetry: () {
+ if (state.chatId != null) {
+ state.getAllMessages(state.chatId!);
+ }
+ },
+ builder: (context, state) {
+ return Stack(
+ children: [
+ SingleChildScrollView(
+ reverse: true,
+ controller: state.scrollController,
+ child: Column(
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ const SizedBox(
+ height: 24,
+ ),
+ // SkeletonImage(
+ // width: 75,
+ // height: 75,
+ // imageUrl: widget.args.bot.image.toString(),
+ // borderRadius: BorderRadius.circular(360),
+ // ),
+ // const SizedBox(
+ // height: 12,
+ // ),
+ // DidvanText(
+ // widget.args.assistantsName ??
+ // widget.args.bot.name.toString(),
+ // fontSize: 17,
+ // fontWeight: FontWeight.bold,
+ // ),
+ if (state.messages.isEmpty)
+ Column(
+ children: [
+ const SizedBox(
+ height: 16,
+ ),
+ Padding(
+ padding: const EdgeInsets.only(left: 60,right: 60),
+ child: Center(
+ child: DidvanText(
+ widget.args.bot.description ?? '',
+ fontSize: 12,
+ color: Theme.of(context)
+ .colorScheme
+ .caption,
+ textAlign: TextAlign.justify,
+ )),
+ ),
+ const SizedBox(
+ height: 100,
+ ),
+ ],
+ )
+ ],
+ ),
+ if (state.messages.isNotEmpty)
+ ListView.builder(
+ itemCount: state.messages.length,
+ shrinkWrap: true,
+ physics: const NeverScrollableScrollPhysics(),
+ padding: EdgeInsets.only(
+ bottom: state.file != null &&
+ !(state.file!.isRecorded)
+ ? 180
+ : 100),
+ itemBuilder: (context, mIndex) {
+ final prompts =
+ state.messages[mIndex].prompts;
+ final time =
+ state.messages[mIndex].dateTime;
+ return Column(
children: [
- const SizedBox(
- height: 16,
- ),
- Padding(
- padding: const EdgeInsets.symmetric(
- horizontal: 20.0),
- child: Center(
- child: DidvanText(
- widget.args.bot.description ?? '',
- fontSize: 12,
- color: Theme.of(context)
- .colorScheme
- .caption,
- textAlign: TextAlign.justify,
- )),
- ),
- const SizedBox(
- height: 100,
+ timeLabel(context, time),
+ ListView.builder(
+ itemCount: prompts.length,
+ shrinkWrap: true,
+ physics:
+ const NeverScrollableScrollPhysics(),
+ itemBuilder: (context, index) {
+ final message = prompts[index];
+
+ return messageBubble(message,
+ context, state, index, mIndex);
+ },
),
],
- )
- ],
- ),
- if (state.messages.isNotEmpty)
- ListView.builder(
- itemCount: state.messages.length,
- shrinkWrap: true,
- physics: const NeverScrollableScrollPhysics(),
- padding: EdgeInsets.only(
- bottom: state.file != null &&
- !(state.file!.isRecorded)
- ? 180
- : 100),
- itemBuilder: (context, mIndex) {
- final prompts =
- state.messages[mIndex].prompts;
- final time =
- state.messages[mIndex].dateTime;
- return Column(
- children: [
- timeLabel(context, time),
- ListView.builder(
- itemCount: prompts.length,
- shrinkWrap: true,
- physics:
- const NeverScrollableScrollPhysics(),
- itemBuilder: (context, index) {
- final message = prompts[index];
-
- return messageBubble(message,
- context, state, index, mIndex);
- },
- ),
- ],
- );
- }),
- ],
- ),
+ );
+ }),
+ ],
),
- Positioned(
- top: 32,
- right: 0,
- child: InkWell(
- onTap: () => scaffKey.currentState!.openDrawer(),
- child: Container(
- width: 46,
- height: 46,
- decoration: BoxDecoration(
- color: Theme.of(context).colorScheme.surface,
- borderRadius: const BorderRadius.only(
- topLeft: Radius.circular(12),
- bottomLeft: Radius.circular(12)),
- boxShadow: DesignConfig.defaultShadow),
- child: Icon(
- DidvanIcons.angle_left_light,
- color: Theme.of(context).colorScheme.title,
- ),
- )),
- )
- ],
- ),
+ ),
+ Positioned(
+ top: 32,
+ right: 0,
+ child: InkWell(
+ onTap: () => scaffKey.currentState!.openDrawer(),
+ child: Container(
+ width: 46,
+ height: 46,
+ decoration: BoxDecoration(
+ color: Theme.of(context).colorScheme.surface,
+ borderRadius: const BorderRadius.only(
+ topLeft: Radius.circular(12),
+ bottomLeft: Radius.circular(12)),
+ boxShadow: DesignConfig.defaultShadow),
+ child: Icon(
+ DidvanIcons.angle_left_light,
+ color: Theme.of(context).colorScheme.title,
+ ),
+ )),
+ )
+ ],
+ );
+ },
+ ),
bottomSheet: Column(
mainAxisSize: MainAxisSize.min,
children: [
- // Platform.isIOS
- // ? AiMessageBarIOS(
- // bot: widget.args.bot,
- // )
- // :
AiMessageBar(
bot: widget.args.bot,
attch: widget.args.attach,
@@ -362,9 +390,7 @@ class _AiChatPageState extends State {
: Column(
children: [
if (file != null)
- (file.isAudio()
- // && (!kIsWeb && !Platform.isIOS)
- )
+ (file.isAudio())
? Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16, vertical: 8),
@@ -428,104 +454,105 @@ class _AiChatPageState extends State {
.toString()
.contains('user') &&
widget.args.assistantsName == null)
- // PopupMenuButton(
- // offset: const Offset(0, 46),
- // onSelected: (value) async {
- // navigatorKey.currentState!.pushNamed(
- // Routes.aiChat,
- // arguments: AiChatArgs(
- // bot: value,
- // prompts: message,
- // isTool: widget.args.isTool ??
- // context
- // .read<
- // HistoryAiChatState>()
- // .bots));
- // },
- // itemBuilder: (BuildContext context) {
- // final bots = widget.args.isTool ??
- // context
- // .read()
- // .bots;
- // return [
- // ...List.generate(
- // bots.length,
- // (index) => PopupMenuItem(
- // value: bots[index],
- // height: 72,
- // child: Container(
- // constraints:
- // const BoxConstraints(
- // maxWidth: 200),
- // child: Row(
- // children: [
- // SkeletonImage(
- // imageUrl: bots[index]
- // .image
- // .toString(),
- // width: 42,
- // height: 42,
- // borderRadius:
- // BorderRadius
- // .circular(360),
- // ),
- // const SizedBox(width: 12),
- // Expanded(
- // child: Directionality(
- // textDirection:
- // TextDirection.ltr,
- // child: DidvanText(
- // bots[index]
- // .name
- // .toString(),
- // maxLines: 1,
- // overflow:
- // TextOverflow
- // .ellipsis,
- // ),
- // ),
- // ),
- // ],
- // ),
- // ),
- // ),
- // )
- // ];
- // },
- // // child: Container(
- // // alignment: Alignment.center,
- // // margin: const EdgeInsets.all(8),
- // // padding: const EdgeInsets.symmetric(
- // // horizontal: 8),
- // // constraints: const BoxConstraints(
- // // maxWidth: 100),
- // // decoration: BoxDecoration(
- // // borderRadius:
- // // DesignConfig.lowBorderRadius,
- // // border: Border.all(
- // // color: Theme.of(context)
- // // .colorScheme
- // // .title)),
- // // child: Row(
- // // children: [
- // // Expanded(
- // // child: Directionality(
- // // textDirection:
- // // TextDirection.ltr,
- // // child: DidvanText(
- // // '${widget.args.assistantsName ?? widget.args.bot.name}',
- // // maxLines: 1,
- // // overflow:
- // // TextOverflow.ellipsis,
- // // ),
- // // ),
- // // ),
- // // const Icon(
- // // DidvanIcons.angle_down_light),
- // // ],
- // // ),
- // // )
- // ),
+ PopupMenuButton(
+ offset: const Offset(0, 46),
+ onSelected: (value) async {
+ navigatorKey.currentState!.pushNamed(
+ Routes.aiChat,
+ arguments: AiChatArgs(
+ bot: value,
+ prompts: message,
+ isTool: widget.args.isTool ??
+ context
+ .read<
+ HistoryAiChatState>()
+ .bots));
+ },
+ itemBuilder: (BuildContext context) {
+ final bots = widget.args.isTool ??
+ context
+ .read()
+ .bots;
+ return [
+ ...List.generate(
+ bots.length,
+ (index) => PopupMenuItem(
+ value: bots[index],
+ height: 72,
+ child: Container(
+ constraints:
+ const BoxConstraints(
+ maxWidth: 200),
+ child: Row(
+ children: [
+ SkeletonImage(
+ imageUrl: bots[index]
+ .image
+ .toString(),
+ width: 42,
+ height: 42,
+ borderRadius:
+ BorderRadius
+ .circular(360),
+ ),
+ const SizedBox(width: 12),
+ Expanded(
+ child: Directionality(
+ textDirection:
+ TextDirection.ltr,
+ child: DidvanText(
+ bots[index]
+ .name
+ .toString(),
+ maxLines: 1,
+ overflow:
+ TextOverflow
+ .ellipsis,
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ )
+ ];
+ },
+ child: const SizedBox(),
+ // Container(
+ // alignment: Alignment.center,
+ // margin: const EdgeInsets.all(8),
+ // padding: const EdgeInsets.symmetric(
+ // horizontal: 8),
+ // constraints: const BoxConstraints(
+ // maxWidth: 100),
+ // decoration: BoxDecoration(
+ // borderRadius:
+ // DesignConfig.lowBorderRadius,
+ // border: Border.all(
+ // color: Theme.of(context)
+ // .colorScheme
+ // .title)),
+ // child: Row(
+ // children: [
+ // Expanded(
+ // child: Directionality(
+ // textDirection:
+ // TextDirection.ltr,
+ // child: DidvanText(
+ // '${widget.args.assistantsName ?? widget.args.bot.name}',
+ // maxLines: 1,
+ // overflow:
+ // TextOverflow.ellipsis,
+ // ),
+ // ),
+ // ),
+ // const Icon(
+ // DidvanIcons.angle_down_light),
+ // ],
+ // ),
+ // )
+ ),
if (message.role
.toString()
.contains('user') &&
@@ -691,7 +718,6 @@ class _AiChatPageState extends State {
children: [
DidvanText(
DateTimeUtils.timeWithAmPm(message.createdAt.toString()),
- // DateTimeUtils.timeWithAmPm(message.createdAt),
style: Theme.of(context).textTheme.labelSmall,
color: Theme.of(context).colorScheme.caption,
),
@@ -733,18 +759,6 @@ class _AiChatPageState extends State {
: TextDirection.rtl,
),
),
- // if (state.file != null && !kIsWeb)
- // FutureBuilder(
- // future: state.file!.main.length(),
- // builder: (context, snapshot) {
- // if (!snapshot.hasData) {
- // return const SizedBox();
- // }
- // return DidvanText(
- // 'File Size ${(snapshot.data! / 1000).round()} KB',
- // fontSize: 12,
- // );
- // })
],
),
)
@@ -772,4 +786,4 @@ class _AiChatPageState extends State {
child: Image.file(file.main)),
);
}
-}
+}
\ No newline at end of file
diff --git a/lib/views/ai/ai_chat_state.dart b/lib/views/ai/ai_chat_state.dart
index aed21fc..8379cb1 100644
--- a/lib/views/ai/ai_chat_state.dart
+++ b/lib/views/ai/ai_chat_state.dart
@@ -290,4 +290,13 @@ class AiChatState extends CoreProvier {
message: 'خطا در برقراری ارتباط', aLertType: ALertType.error));
update();
}
+ void clearChat() {
+ messages.clear();
+ chatId = null;
+ chat = null;
+ file = null;
+ message.clear();
+ isEdite = false;
+ notifyListeners();
+}
}
diff --git a/lib/views/ai/ai_state.dart b/lib/views/ai/ai_state.dart
index 5bc2a02..6919591 100644
--- a/lib/views/ai/ai_state.dart
+++ b/lib/views/ai/ai_state.dart
@@ -1,3 +1,6 @@
+// lib/views/ai/ai_state.dart
+
+import 'package:didvan/models/ai/ai_chat_args.dart';
import 'package:didvan/models/ai/tools_model.dart';
import 'package:didvan/models/enums.dart';
import 'package:didvan/providers/core.dart';
@@ -7,10 +10,23 @@ import 'package:didvan/services/network/request_helper.dart';
class AiState extends CoreProvier {
int page = 0;
Tools? tool;
+ AiChatArgs? currentChatArgs;
+ bool isChatting = false;
bool loading = true;
List? tools;
-
+
+ void startChat(AiChatArgs args) {
+ currentChatArgs = args;
+ isChatting = true;
+ notifyListeners();
+ }
+
+ void endChat() {
+ currentChatArgs = null;
+ isChatting = false;
+ notifyListeners();
+ }
void getTools() async {
final service = RequestService(
@@ -41,4 +57,4 @@ class AiState extends CoreProvier {
this.tool = tool;
update();
}
-}
+}
\ No newline at end of file
diff --git a/lib/views/ai/history_ai_chat_page.dart b/lib/views/ai/history_ai_chat_page.dart
index 8c70262..b8fddb2 100644
--- a/lib/views/ai/history_ai_chat_page.dart
+++ b/lib/views/ai/history_ai_chat_page.dart
@@ -1,3 +1,5 @@
+// lib/views/ai/history_ai_chat_page.dart
+
// ignore_for_file: library_private_types_in_public_api, deprecated_member_use
import 'dart:async';
@@ -62,10 +64,8 @@ class _HistoryAiChatPageState extends State {
child: DidvanScaffold(
hidePlayer: true,
physics: const BouncingScrollPhysics(),
- // floatingActionButton: openAiListBtn(context),
padding: EdgeInsets.zero,
scrollController: scrollController,
-
showSliversFirst: false,
slivers: [
SliverAppBar(
@@ -97,6 +97,7 @@ class _HistoryAiChatPageState extends State {
builder: (context, state, child) {
return SliverStateHandler(
state: state,
+ centerEmptyState: false,
emptyState: EmptyState(
asset: Assets.emptyResult,
title: 'لیست خالی است',
@@ -106,8 +107,6 @@ class _HistoryAiChatPageState extends State {
: state.chats.isEmpty,
placeholder: const _HistoryPlaceholder(),
placeholderCount: 8,
-
- // builder: (context, state, index) => _HistoryPlaceholder(),
builder: (context, state, index) {
final chat = archived
? state.archivedChats[index]
@@ -216,20 +215,20 @@ class _HistoryAiChatPageState extends State {
},
child: InkWell(
onTap: () {
- // if (state.chatsToDelete.isEmpty) {
- navigatorKey.currentState!.pushNamed(Routes.aiChat,
- arguments: AiChatArgs(
- bot: chat.bot!,
- chat: chat,
- assistantsName: chat.assistantsName));
- // } else {
- // if (state.chatsToDelete.contains(chat.id)) {
- // state.chatsToDelete.remove(chat.id!);
- // } else {
- // state.chatsToDelete.add(chat.id!);
- // }
- // }
- // state.update();
+ if (chat.bot != null) {
+ navigatorKey.currentState!.pushNamed(Routes.aiChat,
+ arguments: AiChatArgs(
+ bot: chat.bot!,
+ chat: chat,
+ assistantsName: chat.assistantsName));
+ } else {
+ ScaffoldMessenger.of(context).showSnackBar(
+ const SnackBar(
+ content: Text(
+ 'امکان باز کردن این چت وجود ندارد.'),
+ ),
+ );
+ }
},
onLongPress: () {
if (archived) {
@@ -241,11 +240,6 @@ class _HistoryAiChatPageState extends State {
state.chats[index].copyWith(isEditing: true);
}
state.update();
-
- // if (state.chatsToDelete.isEmpty) {
- // state.chatsToDelete.add(chat.id!);
- // }
- // state.update();
},
child: Container(
padding: const EdgeInsets.symmetric(
@@ -280,7 +274,6 @@ class _HistoryAiChatPageState extends State {
chat.assistantsName ??
chat.bot!.name.toString(),
fontWeight: FontWeight.bold,
- // fontSize: 18,
),
DidvanText(
DateTimeUtils.momentGenerator(
@@ -377,8 +370,6 @@ class _HistoryAiChatPageState extends State {
maxLines: 1,
overflow:
TextOverflow.ellipsis,
- // fontWeight: FontWeight.bold,
- // fontSize: 16,
),
if (chat.prompts != null &&
chat.prompts!.isNotEmpty &&
@@ -475,30 +466,6 @@ class _HistoryAiChatPageState extends State {
),
);
}
-
- // Widget openAiListBtn(BuildContext context) {
- // final watch = context.watch();
- // final state = context.read();
- // return FloatingActionButton(
- // backgroundColor: watch.chatsToDelete.isEmpty
- // ? Theme.of(context).colorScheme.primary
- // : Theme.of(context).colorScheme.error,
- // shape: const OvalBorder(),
- // mini: true,
- // onPressed: () {
- // if (watch.chatsToDelete.isEmpty) {
- // state.getBots();
- // state.search = '';
- // _botsDialogSelect(context);
- // } else {
- // state.addChatToDelete();
- // }
- // },
- // child: watch.chatsToDelete.isEmpty
- // ? const Icon(DidvanIcons.add_regular)
- // : const Icon(DidvanIcons.trash_regular),
- // );
- // }
}
class _HistoryPlaceholder extends StatelessWidget {
@@ -552,4 +519,4 @@ class _HistoryPlaceholder extends StatelessWidget {
),
);
}
-}
+}
\ No newline at end of file
diff --git a/lib/views/ai/widgets/ai_message_bar.dart b/lib/views/ai/widgets/ai_message_bar.dart
index 09c391e..2d9d701 100644
--- a/lib/views/ai/widgets/ai_message_bar.dart
+++ b/lib/views/ai/widgets/ai_message_bar.dart
@@ -297,11 +297,12 @@ class _AiMessageBarState extends State {
MediaQuery.of(context).viewInsets.bottom == 0
? const Padding(
padding: EdgeInsets.fromLTRB(3, 8, 3, 4),
- child: DidvanText(
- 'مدلهای هوش مصنوعی میتوانند اشتباه کنند، صحت اطلاعات مهم را بررسی کنید.',
- fontSize: 11,
- fontWeight: FontWeight.bold,
- ),
+ child: SizedBox(height: 12,)
+ // DidvanText(
+ // 'مدلهای هوش مصنوعی میتوانند اشتباه کنند، صحت اطلاعات مهم را بررسی کنید.',
+ // fontSize: 11,
+ // fontWeight: FontWeight.bold,
+ // ),
)
: const SizedBox(
height: 12,
diff --git a/lib/views/ai/widgets/hoshan_drawer.dart b/lib/views/ai/widgets/hoshan_drawer.dart
index e141bd6..fcc5a14 100644
--- a/lib/views/ai/widgets/hoshan_drawer.dart
+++ b/lib/views/ai/widgets/hoshan_drawer.dart
@@ -1,3 +1,4 @@
+// lib/views/ai/widgets/hoshan_drawer.dart
import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/main.dart';
@@ -8,6 +9,7 @@ import 'package:didvan/models/view/action_sheet_data.dart';
import 'package:didvan/models/view/alert_data.dart';
import 'package:didvan/routes/routes.dart';
import 'package:didvan/utils/action_sheet.dart';
+import 'package:didvan/utils/date_time.dart';
import 'package:didvan/views/ai/history_ai_chat_state.dart';
import 'package:didvan/views/widgets/didvan/divider.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
@@ -28,15 +30,10 @@ class HoshanDrawer extends StatefulWidget {
class _HoshanDrawerState extends State {
@override
- void initState() {
+ initState() {
super.initState();
- WidgetsBinding.instance.addPostFrameCallback((_) {
- final historyState = context.read();
- if (historyState.chats.isEmpty && !historyState.loadinggetAll) {
- historyState.getChats(archived: false);
- }
- });
}
+
@override
Widget build(BuildContext context) {
return Drawer(
@@ -141,13 +138,6 @@ class _HoshanDrawerState extends State {
const SizedBox(
height: 12,
),
- // SearchField(
- // title: 'title',
- // onChanged: (value) {},
- // focusNode: FocusNode()),
- // SizedBox(
- // height: 12,
- // ),
Expanded(
child: CustomScrollView(
slivers: [
@@ -169,11 +159,6 @@ class _HoshanDrawerState extends State {
onRetry: () => state.getChats())
],
)),
-
- // SizedBox(
- // height: 12,
- // ),
- // Text('نمایش قدیمیترها')
],
),
),
@@ -315,11 +300,19 @@ class _HoshanDrawerState extends State {
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: InkWell(
onTap: () {
- navigatorKey.currentState!.pushNamed(Routes.aiChat,
- arguments: AiChatArgs(
- bot: chat.bot!,
- chat: chat,
- assistantsName: chat.assistantsName));
+ if (chat.bot != null) {
+ navigatorKey.currentState!.pushNamed(Routes.aiChat,
+ arguments: AiChatArgs(
+ bot: chat.bot!,
+ chat: chat,
+ assistantsName: chat.assistantsName));
+ } else {
+ ScaffoldMessenger.of(context).showSnackBar(
+ const SnackBar(
+ content: Text('امکان باز کردن این چت وجود ندارد.'),
+ ),
+ );
+ }
},
child: Row(
children: [
@@ -440,4 +433,4 @@ class _HoshanDrawerState extends State {
),
);
}
-}
+}
\ No newline at end of file
diff --git a/lib/views/ai/widgets/tool_category_view_widget.dart b/lib/views/ai/widgets/tool_category_view_widget.dart
index 1d7e867..a5d04a8 100644
--- a/lib/views/ai/widgets/tool_category_view_widget.dart
+++ b/lib/views/ai/widgets/tool_category_view_widget.dart
@@ -1,17 +1,21 @@
+// lib/views/ai/widgets/tool_category_view_widget.dart
+
import 'package:didvan/config/design_config.dart';
import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/models/ai/ai_chat_args.dart';
import 'package:didvan/models/ai/tools_model.dart';
-import 'package:didvan/routes/routes.dart';
+import 'package:didvan/views/ai/ai_state.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:didvan/views/widgets/skeleton_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
+import 'package:provider/provider.dart';
class ToolCategoryViewWidget extends StatelessWidget {
final Tools tool;
- const ToolCategoryViewWidget({Key? key, required this.tool}) : super(key: key);
+ const ToolCategoryViewWidget({Key? key, required this.tool})
+ : super(key: key);
@override
Widget build(BuildContext context) {
@@ -32,15 +36,18 @@ class ToolCategoryViewWidget extends StatelessWidget {
tool.image!,
width: 64,
height: 64,
- placeholderBuilder: (BuildContext context) => const SizedBox(
+ placeholderBuilder: (BuildContext context) =>
+ const SizedBox(
width: 64,
height: 64,
- child: Center(child: CircularProgressIndicator(strokeWidth: 2.0)),
+ child: Center(
+ child: CircularProgressIndicator(strokeWidth: 2.0)),
),
),
const SizedBox(height: 8),
Container(
- padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
+ padding:
+ const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
margin: const EdgeInsets.symmetric(horizontal: 16),
child: DidvanText(
tool.name ?? "ابزار هوش مصنوعی",
@@ -81,19 +88,22 @@ class ToolCategoryViewWidget extends StatelessWidget {
final bot = tool.bots![index];
return InkWell(
onTap: () {
- Navigator.of(context).pushNamed(Routes.aiChat,
- arguments: AiChatArgs(bot: bot, isTool: tool.bots));
+ context
+ .read()
+ .startChat(AiChatArgs(bot: bot, isTool: tool.bots));
},
- child: Container(
+ child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
- topLeft: DesignConfig.highBorderRadius.topLeft,
- topRight: DesignConfig.highBorderRadius.topRight,
- bottomRight: DesignConfig.highBorderRadius.bottomRight,
- bottomLeft: DesignConfig.highBorderRadius.bottomLeft,
- ),
+ topLeft: DesignConfig.highBorderRadius.topLeft,
+ topRight: DesignConfig.highBorderRadius.topRight,
+ bottomRight:
+ DesignConfig.highBorderRadius.bottomRight,
+ bottomLeft: DesignConfig.highBorderRadius.bottomLeft,
+ ),
color: Theme.of(context).colorScheme.surface,
- border: Border.all(color: Theme.of(context).colorScheme.border)),
+ border: Border.all(
+ color: Theme.of(context).colorScheme.border)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
@@ -107,55 +117,67 @@ class ToolCategoryViewWidget extends StatelessWidget {
),
),
),
- Expanded(
+ Expanded(
child: Padding(
- padding: const EdgeInsets.fromLTRB(12, 8, 12, 12),
+ padding:
+ const EdgeInsets.fromLTRB(12, 8, 12, 12),
child: Column(
- mainAxisAlignment: MainAxisAlignment.center,
+ mainAxisAlignment: MainAxisAlignment.center,
children: [
if (bot.image != null)
SkeletonImage(
imageUrl: bot.image!,
- width: 70,
+ width: 70,
height: 70,
borderRadius: BorderRadius.circular(360),
)
else
- Icon(DidvanIcons.ai_solid, size: 50, color: Theme.of(context).colorScheme.primary),
+ Icon(DidvanIcons.ai_solid,
+ size: 50,
+ color: Theme.of(context)
+ .colorScheme
+ .primary),
const SizedBox(height: 15),
Container(
decoration: const BoxDecoration(
- borderRadius: BorderRadius.all(Radius.circular(12)),
+ borderRadius:
+ BorderRadius.all(Radius.circular(12)),
color: customBackgroundColor,
),
-
- padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
+ padding: const EdgeInsets.symmetric(
+ horizontal: 8, vertical: 4),
child: Padding(
padding: const EdgeInsets.all(4.0),
child: DidvanText(
bot.name ?? '',
fontSize: 14,
fontWeight: FontWeight.bold,
- color: Theme.of(context).colorScheme.onPrimary,
+ color: Theme.of(context)
+ .colorScheme
+ .onPrimary,
maxLines: 1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
),
),
),
- if (bot.short != null && bot.short!.isNotEmpty) ...[
+ if (bot.short != null &&
+ bot.short!.isNotEmpty) ...[
const SizedBox(height: 8),
Expanded(
child: DidvanText(
bot.short!,
- fontSize: 10,
- color: Theme.of(context).colorScheme.caption,
- maxLines: 2,
+ fontSize: 10,
+ color: Theme.of(context)
+ .colorScheme
+ .caption,
+ maxLines: 2,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
),
),
- ] else const Spacer(),
+ ] else
+ const Spacer(),
],
),
),
@@ -167,9 +189,11 @@ class ToolCategoryViewWidget extends StatelessWidget {
},
)
else
- Padding(
+ Padding(
padding: const EdgeInsets.all(32.0),
- child: Center(child: DidvanText("هیچ رباتی برای ابزار '${tool.name ?? "انتخابی"}' موجود نیست.")),
+ child: Center(
+ child: DidvanText(
+ "هیچ رباتی برای ابزار '${tool.name ?? "انتخابی"}' موجود نیست.")),
),
],
),
diff --git a/lib/views/ai_section/ai_section_page.dart b/lib/views/ai_section/ai_section_page.dart
index 4342152..b884466 100644
--- a/lib/views/ai_section/ai_section_page.dart
+++ b/lib/views/ai_section/ai_section_page.dart
@@ -1,6 +1,11 @@
+// lib/views/ai_section/ai_section_page.dart
+import 'package:didvan/config/design_config.dart';
+import 'package:didvan/config/theme_data.dart';
+import 'package:didvan/constants/app_icons.dart';
+import 'package:didvan/models/ai/ai_chat_args.dart';
import 'package:didvan/models/ai/tools_model.dart';
-import 'package:didvan/models/enums.dart';
import 'package:didvan/views/ai/ai.dart';
+import 'package:didvan/views/ai/ai_chat_page.dart';
import 'package:didvan/views/ai/widgets/hoshan_drawer.dart';
import 'package:didvan/views/ai_section/widgets/ai_section_bnb.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
@@ -19,7 +24,7 @@ class ImageGenerationScreen extends StatelessWidget {
final aiState = context.watch();
if (aiState.tools == null || aiState.tools!.isEmpty) {
- if (aiState.loading || aiState.appState == AppState.busy) {
+ if (aiState.loading) {
return const Center(child: CircularProgressIndicator());
}
return const Center(
@@ -37,7 +42,7 @@ class VoiceChatScreen extends StatelessWidget {
final aiState = context.watch();
if (aiState.tools == null || aiState.tools!.isEmpty) {
- if (aiState.loading || aiState.appState == AppState.busy) {
+ if (aiState.loading) {
return const Center(child: CircularProgressIndicator());
}
return const Center(
@@ -56,7 +61,7 @@ class ChartAnalysisScreen extends StatelessWidget {
final aiState = context.watch();
if (aiState.tools == null || aiState.tools!.isEmpty) {
- if (aiState.loading || aiState.appState == AppState.busy) {
+ if (aiState.loading) {
return const Center(child: CircularProgressIndicator());
}
return const Center(
@@ -81,7 +86,7 @@ class TranslationScreen extends StatelessWidget {
final aiState = context.watch();
if (aiState.tools == null || aiState.tools!.isEmpty) {
- if (aiState.loading || aiState.appState == AppState.busy) {
+ if (aiState.loading) {
return const Center(child: CircularProgressIndicator());
}
return const Center(
@@ -97,7 +102,6 @@ class TranslationScreen extends StatelessWidget {
return ToolCategoryViewWidget(tool: translationToolCategory);
}
}
-
class AiSectionPage extends StatefulWidget {
const AiSectionPage({super.key});
@@ -105,25 +109,22 @@ class AiSectionPage extends StatefulWidget {
State createState() => _AiSectionPageState();
}
-class _AiSectionPageState extends State
- with SingleTickerProviderStateMixin {
- late TabController _tabController;
+class _AiSectionPageState extends State {
int _currentTabIndex = 2;
final GlobalKey _aiSectionScaffoldKey =
GlobalKey();
+ final List _pages = const [
+ ImageGenerationScreen(),
+ VoiceChatScreen(),
+ Ai(),
+ ChartAnalysisScreen(),
+ TranslationScreen(),
+ ];
+
@override
void initState() {
super.initState();
- _tabController = TabController(length: 5, vsync: this, initialIndex: 2);
- _tabController.addListener(() {
- if (mounted) {
- setState(() {
- _currentTabIndex = _tabController.index;
- });
- }
- });
-
WidgetsBinding.instance.addPostFrameCallback((_) {
final historyAiChatState = context.read();
if (historyAiChatState.bots.isEmpty) {
@@ -131,28 +132,64 @@ class _AiSectionPageState extends State
}
final aiState = context.read();
- aiState.page = 0;
+ aiState.endChat();
if (aiState.tools == null) {
aiState.getTools();
}
});
}
- @override
- void dispose() {
- _tabController.dispose();
- super.dispose();
+ void _onTabChanged(int index) {
+ final aiState = context.read();
+ aiState.endChat();
+
+ setState(() {
+ _currentTabIndex = index;
+ });
+
+ if (aiState.tools != null && aiState.tools!.isNotEmpty) {
+ Tools? tool;
+ switch (index) {
+ case 0:
+ tool = aiState.tools![0];
+ break;
+ case 1:
+ tool = aiState.tools!.last;
+ break;
+ case 2:
+ return;
+ case 3:
+ if (aiState.tools!.length > 1) {
+ tool = aiState.tools![1];
+ }
+ break;
+ case 4:
+ if (aiState.tools!.length > 2) {
+ tool = aiState.tools![2];
+ }
+ break;
+ }
+
+ if (tool != null && tool.bots != null && tool.bots!.isNotEmpty) {
+ final firstBot = tool.bots!.first;
+ aiState.startChat(AiChatArgs(bot: firstBot));
+ }
+ }
}
@override
Widget build(BuildContext context) {
+ final aiState = context.watch();
+
return Scaffold(
key: _aiSectionScaffoldKey,
appBar: HoshanAppBar(
onBack: () {
- final aiState = context.read();
- if (aiState.page != 0) {
- aiState.goToAi();
+ if (aiState.isChatting) {
+ aiState.endChat();
+ setState(() {
+ _currentTabIndex = 2;
+ });
} else {
Navigator.of(context).pop();
}
@@ -160,22 +197,40 @@ class _AiSectionPageState extends State
withActions: true,
),
drawer: HoshanDrawer(scaffKey: _aiSectionScaffoldKey),
- body: TabBarView(
- controller: _tabController,
- physics: const NeverScrollableScrollPhysics(),
- children: const [
- ImageGenerationScreen(),
- VoiceChatScreen(),
- Ai(),
- ChartAnalysisScreen(),
- TranslationScreen(),
+ body: Stack(
+ children: [
+ aiState.isChatting
+ ? AiChatPage(args: aiState.currentChatArgs!)
+ : IndexedStack(
+ index: _currentTabIndex,
+ children: _pages,
+ ),
+ Positioned(
+ top: 32,
+ right: 0,
+ child: InkWell(
+ onTap: () => _aiSectionScaffoldKey.currentState?.openDrawer(),
+ child: Container(
+ width: 46,
+ height: 46,
+ decoration: BoxDecoration(
+ color: Theme.of(context).colorScheme.surface,
+ borderRadius: const BorderRadius.only(
+ topLeft: Radius.circular(12),
+ bottomLeft: Radius.circular(12)),
+ boxShadow: DesignConfig.defaultShadow),
+ child: Icon(
+ DidvanIcons.angle_left_light,
+ color: Theme.of(context).colorScheme.title,
+ ),
+ ),
+ ),
+ )
],
),
bottomNavigationBar: AiSectionBNB(
currentTabIndex: _currentTabIndex,
- onTabChanged: (index) {
- _tabController.animateTo(index);
- },
+ onTabChanged: _onTabChanged,
),
);
}
diff --git a/lib/views/ai_section/widgets/ai_section_bnb.dart b/lib/views/ai_section/widgets/ai_section_bnb.dart
index 6dac1e0..6fa50cd 100644
--- a/lib/views/ai_section/widgets/ai_section_bnb.dart
+++ b/lib/views/ai_section/widgets/ai_section_bnb.dart
@@ -1,14 +1,8 @@
import 'package:didvan/config/design_config.dart';
import 'package:didvan/config/theme_data.dart';
-import 'package:didvan/models/ai/ai_chat_args.dart';
-import 'package:didvan/models/ai/tools_model.dart';
-import 'package:didvan/routes/routes.dart';
-import 'package:didvan/services/webview.dart';
-import 'package:didvan/views/ai/ai_state.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
-import 'package:provider/provider.dart';
class AiSectionBNB extends StatelessWidget {
final int currentTabIndex;
@@ -21,15 +15,20 @@ class AiSectionBNB extends StatelessWidget {
@override
Widget build(BuildContext context) {
const String cameraSolid = 'lib/assets/icons/houshanNav/imagegeneratorS.svg';
- const String cameraRegular = 'lib/assets/icons/houshanNav/imagegeneratorU.svg';
- const String micSolid = 'lib/assets/icons/houshanNav/aichatS.svg';
- const String micRegular = 'lib/assets/icons/houshanNav/aichatU.svg';
- const String aiSolid = 'lib/assets/icons/houshanNav/houshan.svg';
- const String aiRegular = 'lib/assets/icons/houshanNav/houshan.svg';
+ const String cameraRegular =
+ 'lib/assets/icons/houshanNav/imagegeneratorU.svg';
+ // const String micSolid = 'lib/assets/icons/houshanNav/aichatS.svg';
+ // const String micRegular = 'lib/assets/icons/houshanNav/aichatU.svg';
+ const String aiSolid =
+ 'lib/assets/icons/houshanNav/streamline-flex_ai-scanner-robot-remix.svg';
+ const String aiRegular =
+ 'lib/assets/icons/houshanNav/streamline-flex_ai-scanner-robot.svg';
const String searchSolid = 'lib/assets/icons/houshanNav/searchS.svg';
const String searchRegular = 'lib/assets/icons/houshanNav/searchU.svg';
- const String translateSolid = 'lib/assets/icons/houshanNav/translateS.svg';
- const String translateRegular = 'lib/assets/icons/houshanNav/translateU.svg';
+ const String translateSolid =
+ 'lib/assets/icons/houshanNav/translateS.svg';
+ const String translateRegular =
+ 'lib/assets/icons/houshanNav/translateU.svg';
return Container(
height: 72,
@@ -50,91 +49,38 @@ class AiSectionBNB extends StatelessWidget {
children: [
_AiNavBarItem(
isSelected: currentTabIndex == 0,
- title: 'عکس ساز',
+ title: 'تصویرساز',
selectedIcon: cameraSolid,
unselectedIcon: cameraRegular,
- onTap: () {
- final aiState = context.read();
- if (aiState.tools != null && aiState.tools!.isNotEmpty) {
- final Tools imageGenTool = aiState.tools![0]; // ابزار عکس ساز
- if (imageGenTool.bots != null && imageGenTool.bots!.isNotEmpty) {
- final bot = imageGenTool.bots!.first;
- Navigator.of(context).pushNamed(
- Routes.aiChat,
- arguments: AiChatArgs(bot: bot, isTool: imageGenTool.bots),
- );
- }
- } else {
- ScaffoldMessenger.of(context).showSnackBar(
- const SnackBar(content: Text('ابزار عکس ساز در حال بارگذاری است...')),
- );
- }
- },
- ),
- _AiNavBarItem(
- isSelected: currentTabIndex == 1,
- title: 'چت صوتی',
- selectedIcon: micSolid,
- unselectedIcon: micRegular,
- onTap: () {
- NativeWebViewLauncher.openWebView(
- 'https://www.aisada.ir/app/page1.html');
- },
+ onTap: () => onTabChanged(0),
),
+ // _AiNavBarItem(
+ // isSelected: currentTabIndex == 1,
+ // title: 'چت صوتی',
+ // selectedIcon: micSolid,
+ // unselectedIcon: micRegular,
+ // onTap: () => onTabChanged(1),
+ // ),
_AiNavBarItem(
isSelected: currentTabIndex == 2,
- title: '',
+ title: 'گفتوگو',
selectedIcon: aiSolid,
unselectedIcon: aiRegular,
onTap: () => onTabChanged(2),
),
_AiNavBarItem(
isSelected: currentTabIndex == 3,
- title: 'جست و جو',
+ title: 'جستوجو',
selectedIcon: searchSolid,
unselectedIcon: searchRegular,
- onTap: () {
- final aiState = context.read();
- // نکته: طبق کد شما، تب جستجو (اندیس ۳) ویجت تحلیل نمودار را نمایش میدهد
- // که از ابزار اندیس ۱ استفاده میکند.
- if (aiState.tools != null && aiState.tools!.length > 1) {
- final Tools chartAnalysisTool = aiState.tools![1];
- if (chartAnalysisTool.bots != null && chartAnalysisTool.bots!.isNotEmpty) {
- final bot = chartAnalysisTool.bots!.first;
- Navigator.of(context).pushNamed(
- Routes.aiChat,
- arguments: AiChatArgs(bot: bot, isTool: chartAnalysisTool.bots),
- );
- }
- } else {
- ScaffoldMessenger.of(context).showSnackBar(
- const SnackBar(content: Text('ابزار جستجو در حال بارگذاری است...')),
- );
- }
- },
+ onTap: () => onTabChanged(3),
),
_AiNavBarItem(
isSelected: currentTabIndex == 4,
title: 'ترجمه',
selectedIcon: translateSolid,
unselectedIcon: translateRegular,
- onTap: () {
- final aiState = context.read();
- if (aiState.tools != null && aiState.tools!.length > 2) {
- final Tools translationToolCategory = aiState.tools![2];
- if (translationToolCategory.bots != null && translationToolCategory.bots!.isNotEmpty) {
- final gptTranslatorBot = translationToolCategory.bots!.first;
- Navigator.of(context).pushNamed(
- Routes.aiChat,
- arguments: AiChatArgs(bot: gptTranslatorBot, isTool: translationToolCategory.bots),
- );
- }
- } else {
- ScaffoldMessenger.of(context).showSnackBar(
- const SnackBar(content: Text('ابزار ترجمه در حال بارگذاری است...')),
- );
- }
- },
+ onTap: () => onTabChanged(4),
),
],
),
@@ -142,7 +88,6 @@ class AiSectionBNB extends StatelessWidget {
}
}
-
class _AiNavBarItem extends StatelessWidget {
final VoidCallback onTap;
final bool isSelected;
@@ -161,7 +106,6 @@ class _AiNavBarItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
-
final double iconSize = title.isEmpty ? 50.0 : 32.0;
return Expanded(
diff --git a/lib/views/authentication/authentication_state.dart b/lib/views/authentication/authentication_state.dart
index 013740b..00de5d3 100644
--- a/lib/views/authentication/authentication_state.dart
+++ b/lib/views/authentication/authentication_state.dart
@@ -43,10 +43,14 @@ class AuthenticationState extends CoreProvier {
currentPageIndex = 2;
}
} else {
- appState = AppState.failed;
- ActionSheetUtils(navigatorKey.currentContext!)
- .showAlert(AlertData(message: service.errorMessage));
+ appState = AppState.failed;
+ String message = service.errorMessage;
+ if (service.statusCode == 404) {
+ message = 'کاربر موجود نمیباشد.';
}
+ ActionSheetUtils(navigatorKey.currentContext!)
+ .showAlert(AlertData(message: message));
+}
}
Future login(UserProvider userProvider) async {
diff --git a/lib/views/authentication/screens/verification.dart b/lib/views/authentication/screens/verification.dart
index ea3c8b5..6d0ec09 100644
--- a/lib/views/authentication/screens/verification.dart
+++ b/lib/views/authentication/screens/verification.dart
@@ -9,9 +9,11 @@ import 'package:didvan/views/authentication/authentication_state.dart';
import 'package:didvan/views/authentication/widgets/authentication_layout.dart';
import 'package:didvan/views/widgets/didvan/button.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
+import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:pin_code_fields/pin_code_fields.dart';
import 'package:provider/provider.dart';
+import 'package:sms_autofill/sms_autofill.dart';
class Verification extends StatefulWidget {
const Verification({Key? key}) : super(key: key);
@@ -39,7 +41,23 @@ class _VerificationState extends State {
);
_handleTimer();
super.initState();
+ _listenForSms();
}
+
+ Future _listenForSms() async {
+ if (kDebugMode) {
+ print("<<<<< در حال تلاش برای دریافت امضای برنامه >>>>>");
+ }
+
+ final appSignature = await SmsAutoFill().getAppSignature;
+
+ if (kDebugMode) {
+ print("App Signature: $appSignature");
+ }
+
+ await SmsAutoFill().listenForCode();
+}
+
@override
Widget build(BuildContext context) {
diff --git a/lib/views/authentication/widgets/authentication_layout.dart b/lib/views/authentication/widgets/authentication_layout.dart
index 1ea1962..bd4a0cb 100644
--- a/lib/views/authentication/widgets/authentication_layout.dart
+++ b/lib/views/authentication/widgets/authentication_layout.dart
@@ -1,7 +1,7 @@
// ignore_for_file: deprecated_member_use
import 'package:didvan/views/authentication/widgets/authentication_app_bar.dart';
-import 'package:didvan/views/widgets/logos/didvan_vertical_logo.dart';
+import 'package:didvan/views/widgets/logos/didvan_horizontal_logo.dart';
import 'package:flutter/material.dart';
class AuthenticationLayout extends StatelessWidget {
@@ -23,10 +23,10 @@ class AuthenticationLayout extends StatelessWidget {
toolbarHeight: 56,
backgroundColor: Theme.of(context).colorScheme.background,
flexibleSpace: Padding(
- padding: EdgeInsets.only(
+ padding: const EdgeInsets.only(
left: 16,
right: 16,
- top: MediaQuery.of(context).padding.top,
+ top: 7,
),
child: AuthenticationAppBar(
title: appBarTitle,
@@ -41,7 +41,9 @@ class AuthenticationLayout extends StatelessWidget {
bottom: 40,
),
sliver: const SliverToBoxAdapter(
- child: DidvanHorizontalLogo(),
+ child: DidvanVerticalLogo(
+ height: 145,
+ ),
),
),
SliverPadding(
diff --git a/lib/views/home/home.dart b/lib/views/home/home.dart
index baebb6c..33a7093 100644
--- a/lib/views/home/home.dart
+++ b/lib/views/home/home.dart
@@ -63,13 +63,11 @@ class _HomeState extends State
),
],
),
- const SizedBox(height: 8),
-
+ const SizedBox(height: 15),
SvgPicture.asset(Assets.horizontalLogoWithText, height: 80),
const SizedBox(height: 24),
-
DidvanText(
- 'به دیدوان، چشم همیشه باز مدیران خوش آمدید',
+ 'به سوپر اپلیکیشن دیدوان خوش آمدید',
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleMedium,
),
@@ -82,42 +80,47 @@ class _HomeState extends State
data: ActionSheetData(
backgroundColor: Theme.of(context).colorScheme.background,
isBackgroundDropBlur: true,
- content: Column(
+ content: Stack(
children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- InkWrapper(
- onPressed: () {
- Future.delayed(
- Duration.zero,
- () => Navigator.of(context).pop(),
- );
- },
- child: const Icon(
- DidvanIcons.close_solid,
- size: 24,
+ Padding(
+ padding: const EdgeInsets.only(top: 24.0),
+ child: Column(
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ DidvanText(
+ 'شخصی سازی محتوا',
+ style:
+ Theme.of(context).textTheme.displaySmall,
+ color: Theme.of(context).colorScheme.text,
+ ),
+ ],
),
- ),
- DidvanText(
- 'شخصی سازی محتوا',
- style: Theme.of(context).textTheme.displaySmall,
- color: Theme.of(context).colorScheme.text,
- ),
- const InkWrapper(
- child: Icon(
- DidvanIcons.close_regular,
- size: 24,
- color: Colors.transparent,
+ const SizedBox(
+ height: 12,
),
+ const DidvanText(
+ "کاربر گرامی\nلطفا جهت شخصیسازی و استفاده بهتر از برنامه، دستهبندیهای مورد علاقه خود و زمان دریافت اعلانات را انتخاب نمایید.")
+ ],
+ ),
+ ),
+ Positioned(
+ top: 0,
+ left: 0,
+ child: InkWrapper(
+ onPressed: () {
+ Future.delayed(
+ Duration.zero,
+ () => Navigator.of(context).pop(),
+ );
+ },
+ child: const Icon(
+ DidvanIcons.close_solid,
+ size: 24,
),
- ],
+ ),
),
- const SizedBox(
- height: 12,
- ),
- const DidvanText(
- "کاربر گرامی\nلطفا جهت شخصیسازی و استفاده بهتر از برنامه، دستهبندیهای مورد علاقه خود و زمان دریافت اعلانات را انتخاب نمایید.")
],
),
onConfirmed: () {
@@ -141,20 +144,22 @@ class _HomeState extends State
if (widget.showDialogs ?? false) {
_showDialog(context);
}
- // if (!kIsWeb) {
- // NotificationService.startListeningNotificationEvents();
- // }
final state = context.read();
DesignConfig.updateSystemUiOverlayStyle();
_tabController = TabController(length: 4, vsync: this, initialIndex: 0);
state.tabController = _tabController;
+
+ // این قسمت را اضافه یا جایگزین کنید
_tabController.addListener(() {
state.currentPageIndex = _tabController.index;
if (_tabController.index == 2) {
- final state = context.read();
-
- state.getBots();
+ // با هر بار ورود به تب هوشان، لیست چتها ریست میشود
+ final historyState = context.read();
+ historyState.chats.clear();
+ historyState.archivedChats.clear();
+ historyState.update(); // برای اطمینان از بهروزرسانی UI
+ historyState.getBots();
}
});
if (!kIsWeb) {
diff --git a/lib/views/home/main/main_page.dart b/lib/views/home/main/main_page.dart
index 4f85f62..c063b76 100644
--- a/lib/views/home/main/main_page.dart
+++ b/lib/views/home/main/main_page.dart
@@ -208,7 +208,7 @@ class _SwotSection extends StatelessWidget {
/// Swot Items Slider
DidvanSlider(
- height: 300,
+ height: 335,
itemCount: items.length,
viewportFraction: 0.65,
itemBuilder: (context, index, realIndex) => Padding(
diff --git a/lib/views/home/main/main_page_state.dart b/lib/views/home/main/main_page_state.dart
index 727bb19..ea0c12a 100644
--- a/lib/views/home/main/main_page_state.dart
+++ b/lib/views/home/main/main_page_state.dart
@@ -33,11 +33,9 @@ class MainPageState extends CoreProvier {
Future _fetchStories() async {
try {
stories = await StoryService.getStories();
- // [اضافه شود] تعداد استوری های دریافت شده را چاپ کنید
print("Fetched ${stories.length} stories.");
} catch (e) {
stories = [];
- // [اضافه شود] خطای رخ داده را چاپ کنید
debugPrint("Could not fetch stories: $e");
}
}
diff --git a/lib/views/home/main/widgets/main_content.dart b/lib/views/home/main/widgets/main_content.dart
index 5fe9349..d0de86a 100644
--- a/lib/views/home/main/widgets/main_content.dart
+++ b/lib/views/home/main/widgets/main_content.dart
@@ -3,7 +3,6 @@
import 'package:didvan/config/theme_data.dart';
import 'package:didvan/views/home/main/widgets/banner.dart';
import 'package:didvan/views/home/widgets/categories.dart';
-import 'package:didvan/views/widgets/ai_banner.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:flutter/material.dart';
diff --git a/lib/views/home/main/widgets/story_section.dart b/lib/views/home/main/widgets/story_section.dart
index ca435c2..4f8a909 100644
--- a/lib/views/home/main/widgets/story_section.dart
+++ b/lib/views/home/main/widgets/story_section.dart
@@ -1,7 +1,6 @@
import 'package:didvan/models/story_model.dart';
import 'package:didvan/routes/routes.dart';
import 'package:flutter/material.dart';
-import 'package:flutter_svg/svg.dart';
class StorySection extends StatelessWidget {
final List stories;
@@ -67,8 +66,8 @@ class _StoryCircle extends StatelessWidget {
valueListenable: allStoriesViewed,
builder: (context, isViewed, child) {
return Container(
- width: 80.0,
- height: 80.0,
+ width: 85.0,
+ height: 85.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: isViewed
@@ -80,8 +79,8 @@ class _StoryCircle extends StatelessWidget {
)
: const LinearGradient(
colors: [
- Color.fromARGB(255, 27, 60, 79),
- Color.fromARGB(255, 27, 60, 79)
+ Color.fromARGB(255, 1, 35, 54),
+ Color.fromARGB(255, 178, 4, 54),
],
begin: Alignment.topRight,
end: Alignment.bottomLeft,
diff --git a/lib/views/home/main/widgets/swot_item_card.dart b/lib/views/home/main/widgets/swot_item_card.dart
index e7bd4c0..1ad2b51 100644
--- a/lib/views/home/main/widgets/swot_item_card.dart
+++ b/lib/views/home/main/widgets/swot_item_card.dart
@@ -1,6 +1,7 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cached_network_image_platform_interface/cached_network_image_platform_interface.dart';
import 'package:didvan/config/theme_data.dart';
+import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/models/home_page_content/swot.dart';
import 'package:didvan/services/app_initalizer.dart';
import 'package:didvan/services/network/request.dart';
@@ -22,6 +23,23 @@ class SwotItemCard extends StatefulWidget {
}
class _SwotItemCardState extends State {
+ String _getCategoryName(String category) {
+ switch (category) {
+ case 'MACRO_TRENDS':
+ return 'کلان روند';
+ case 'INDUSTRY_ENVIRONMENT':
+ return 'محیط صنعت';
+ case 'CONCEPTS':
+ return 'مفاهیم';
+ case 'MACRO_ENVIRONMENT':
+ return 'محیط کلان';
+ case 'INVESTMENTS':
+ return 'سرمایه گذاری';
+ default:
+ return category;
+ }
+ }
+
@override
Widget build(BuildContext context) {
return GestureDetector(
@@ -33,8 +51,8 @@ class _SwotItemCardState extends State {
);
},
child: Container(
+ height: 500 ,
width: 250,
- height: 50,
margin: const EdgeInsets.only(right: 0),
padding: const EdgeInsets.all(0),
decoration: BoxDecoration(
@@ -82,7 +100,7 @@ class _SwotItemCardState extends State {
),
),
Padding(
- padding: const EdgeInsets.all(8.0),
+ padding: const EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 0),
child: Text(
widget.item.title,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
@@ -91,7 +109,6 @@ class _SwotItemCardState extends State {
overflow: TextOverflow.ellipsis,
),
),
- const SizedBox(height: 5),
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
@@ -128,24 +145,25 @@ class _SwotItemCardState extends State {
)
],
),
- // GestureDetector(
- // onTap: () {}, child: Icon(DidvanIcons.bookmark_solid)
- // // Icon(
- // // widget.item.marked
- // // ? DidvanIcons.bookmark_solid
- // // : DidvanIcons.bookmark_regular,
- // // color: widget.item.marked
- // // ? Theme.of(context).colorScheme.secondary
- // // : Theme.of(context).colorScheme.caption,
- // // ),
- // ),
+ const SizedBox(height: 10),
+ Row(
+ children: [
+ const Icon(DidvanIcons.puzzle_light,size: 17,),
+ const SizedBox(width: 5,),
+ Text(
+ _getCategoryName(widget.item.category),
+ style: Theme.of(context).textTheme.bodyMedium,
+ ),
+ ],
+ ),
+ const SizedBox(height: 30),
],
),
),
],
),
Positioned(
- bottom: 0,
+ bottom: 3,
left: 0,
child: BookmarkIcon(postId: widget.item.id),
)
@@ -154,4 +172,4 @@ class _SwotItemCardState extends State {
),
);
}
-}
+}
\ No newline at end of file
diff --git a/lib/views/podcasts/studio_details/studio_details.mobile.dart b/lib/views/podcasts/studio_details/studio_details.mobile.dart
index 5240a0a..f01af12 100644
--- a/lib/views/podcasts/studio_details/studio_details.mobile.dart
+++ b/lib/views/podcasts/studio_details/studio_details.mobile.dart
@@ -3,6 +3,7 @@
import 'package:chewie/chewie.dart';
import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/assets.dart';
+import 'package:didvan/models/studio_details_data.dart';
import 'package:didvan/models/view/app_bar_data.dart';
import 'package:didvan/services/media/media.dart';
import 'package:didvan/views/podcasts/studio_details/studio_details_state.dart';
@@ -26,9 +27,8 @@ class StudioDetails extends StatefulWidget {
}
class _StudioDetailsState extends State {
- // ignore: unused_field
int _currentlyPlayingId = 0;
- late VideoPlayerController _videoPlayerController;
+ VideoPlayerController? _videoPlayerController;
ChewieController? _chewieController;
@override
@@ -40,26 +40,9 @@ class _StudioDetailsState extends State {
Future.delayed(
Duration.zero,
() => state.getStudioDetails(widget.pageData['id']).then((_) {
- if (!mounted) return;
- _videoPlayerController = VideoPlayerController.network(
- state.studio.link,
- );
- _videoPlayerController.initialize().then((_) {
- _chewieController = ChewieController(
- videoPlayerController: _videoPlayerController,
- customControls: const PrimaryControls(),
- autoPlay: true,
- looping: true,
- aspectRatio: 16 / 9,
- materialProgressColors: ChewieProgressColors(
- playedColor: Theme.of(context).colorScheme.title,
- handleColor: Theme.of(context).colorScheme.title,
- ),
- );
- setState(() {
- _currentlyPlayingId = state.studio.id;
- });
- });
+ if (mounted) {
+ _initializePlayer(state.studio);
+ }
}),
);
@@ -72,9 +55,9 @@ class _StudioDetailsState extends State {
() => Navigator.of(context).pushNamed(
Routes.mentions,
arguments: {
- 'id': state.studio.id,
+ 'id': context.read().studio.id,
'type': 'studio',
- 'title': state.studio.title,
+ 'title': context.read().studio.title,
},
),
);
@@ -82,99 +65,135 @@ class _StudioDetailsState extends State {
}
}
+ Future _initializePlayer(StudioDetailsData studio) async {
+ // Disposing old controllers before creating new ones.
+ _videoPlayerController?.dispose();
+ _chewieController?.dispose();
+
+ _videoPlayerController = VideoPlayerController.network(studio.link);
+
+ try {
+ await _videoPlayerController!.initialize();
+ if (mounted) {
+ setState(() {
+ _chewieController = ChewieController(
+ videoPlayerController: _videoPlayerController!,
+ customControls: const PrimaryControls(),
+ autoPlay: true,
+ looping: true,
+ aspectRatio: 16 / 9,
+ materialProgressColors: ChewieProgressColors(
+ playedColor: Theme.of(context).colorScheme.title,
+ handleColor: Theme.of(context).colorScheme.title,
+ ),
+ );
+ _currentlyPlayingId = studio.id;
+ });
+ }
+ } catch (e) {
+ debugPrint("Error initializing video player: $e");
+ }
+ }
+
@override
Widget build(BuildContext context) {
final d = MediaQuery.of(context);
return Consumer(
- builder: (context, state, child) => StateHandler(
- state: state,
- onRetry: () {
- try {
- state.getStudioDetails(state.studio.id);
- } catch (e) {
- state.getStudioDetails(widget.pageData['id']);
- }
- },
- builder: (context, state) {
- if (!state.isStudioLoaded) {
- return Center(
- child: Image.asset(
- Assets.loadingAnimation,
- width: 100,
- height: 100,
+ builder: (context, state, child) {
+ if (state.isStudioLoaded && _currentlyPlayingId != state.studio.id) {
+ Future.microtask(() => _initializePlayer(state.studio));
+ }
+ return StateHandler(
+ state: state,
+ onRetry: () {
+ try {
+ state.getStudioDetails(state.studio.id);
+ } catch (e) {
+ state.getStudioDetails(widget.pageData['id']);
+ }
+ },
+ builder: (context, state) {
+ if (!state.isStudioLoaded) {
+ return Center(
+ child: Image.asset(
+ Assets.loadingAnimation,
+ width: 100,
+ height: 100,
+ ),
+ );
+ }
+ return WillPopScope(
+ onWillPop: () async {
+ if (MediaService.currentPodcast != null) {
+ state.studio = MediaService.currentPodcast!;
+ }
+ state.handleTracking(id: state.studio.id);
+ return true;
+ },
+ child: SafeArea(
+ child: Scaffold(
+ backgroundColor: Theme.of(context).colorScheme.surface,
+ appBar: PreferredSize(
+ preferredSize: const Size.fromHeight(56),
+ child: DidvanAppBar(
+ appBarData: AppBarData(
+ trailing: BookmarkButton(
+ itemId: state.studio.id,
+ type: 'video',
+ value: state.studio.marked,
+ onMarkChanged: (value) {
+ widget.pageData['onMarkChanged'](
+ state.studio.id, value);
+ },
+ gestureSize: 48,
+ ),
+ isSmall: true,
+ title: state.studio.title,
+ ),
+ ),
+ ),
+ body: SingleChildScrollView(
+ child: SizedBox(
+ height: d.size.height - d.padding.top - 56,
+ child: Column(
+ children: [
+ AspectRatio(
+ aspectRatio: 16 / 9,
+ child: (_chewieController != null &&
+ _chewieController!
+ .videoPlayerController.value.isInitialized)
+ ? Chewie(controller: _chewieController!)
+ : Center(
+ child: Image.asset(
+ Assets.loadingAnimation,
+ width: 100,
+ height: 100,
+ ),
+ ),
+ ),
+ Expanded(
+ child: StudioDetailsWidget(
+ onMarkChanged: (id, value) => widget
+ .pageData['onMarkChanged'](id, value, true),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
),
);
- }
- return WillPopScope(
- onWillPop: () async {
- if (MediaService.currentPodcast != null) {
- state.studio = MediaService.currentPodcast!;
- }
- state.handleTracking(id: state.studio.id);
- return true;
- },
- child: SafeArea(
- child: Scaffold(
- backgroundColor: Theme.of(context).colorScheme.surface,
- appBar: PreferredSize(
- preferredSize: const Size.fromHeight(56),
- child: DidvanAppBar(
- appBarData: AppBarData(
- trailing: BookmarkButton(
- itemId: state.studio.id,
- type: 'video',
- value: state.studio.marked,
- onMarkChanged: (value) {
- widget.pageData['onMarkChanged'](
- state.studio.id, value);
- },
- gestureSize: 48,
- ),
- isSmall: true,
- title: state.studio.title,
- ),
- ),
- ),
- body: SingleChildScrollView(
- child: SizedBox(
- height: d.size.height - d.padding.top - 56,
- child: Column(
- children: [
- AspectRatio(
- aspectRatio: 16 / 9,
- child: _chewieController != null
- ? Chewie(controller: _chewieController!)
- : Center(
- child: Image.asset(
- Assets.loadingAnimation,
- width: 100,
- height: 100,
- ),
- ),
- ),
- Expanded(
- child: StudioDetailsWidget(
- onMarkChanged: (id, value) => widget
- .pageData['onMarkChanged'](id, value, true),
- ),
- ),
- ],
- ),
- ),
- ),
- ),
- ),
- );
- },
- ),
+ },
+ );
+ },
);
}
@override
void dispose() {
- _videoPlayerController.pause();
- _videoPlayerController.dispose();
+ _videoPlayerController?.dispose();
_chewieController?.dispose();
super.dispose();
}
-}
+}
\ No newline at end of file
diff --git a/lib/views/podcasts/studio_details/studio_details_state.dart b/lib/views/podcasts/studio_details/studio_details_state.dart
index e337f61..be39e35 100644
--- a/lib/views/podcasts/studio_details/studio_details_state.dart
+++ b/lib/views/podcasts/studio_details/studio_details_state.dart
@@ -18,11 +18,14 @@ class StudioDetailsState extends CoreProvier {
StudioRequestArgs? args;
StudioRequestArgs? podcastArgs;
final List relatedQueue = [];
- bool _positionListenerActivated = false;
AppState alongSideState = AppState.idle;
int _trackingTimerCounter = 0;
Timer? _trackingTimer;
+ // BEGIN: ADD THIS LINE
+ StreamSubscription? _positionSubscription;
+ // END: ADD THIS LINE
+
int _selectedDetailsIndex = 0;
Timer? timer;
int timerValue = 10;
@@ -134,6 +137,8 @@ class StudioDetailsState extends CoreProvier {
}
Future _handlePodcastPlayback(StudioDetailsData studio) async {
+ _positionSubscription?.cancel();
+
if (args?.type == 'podcast') {
MediaService.currentPodcast = studio;
MediaService.podcastPlaylistArgs = args;
@@ -149,20 +154,21 @@ class StudioDetailsState extends CoreProvier {
}
},
);
- if (nextStudio != null && !_positionListenerActivated) {
- _positionListenerActivated = true;
- MediaService.audioPlayer.positionStream.listen((event) {
- if (MediaService.audioPlayerTag?.contains('message') == true) {
+ if (nextStudio != null) {
+ _positionSubscription =
+ MediaService.audioPlayer.positionStream.listen((event) {
+ if (this.args?.type != 'podcast' ||
+ MediaService.audioPlayerTag?.contains('message') == true) {
return;
}
final duration =
- MediaService.duration ?? Duration(seconds: studio.duration);
- if (event.compareTo(duration) > 0 && nextStudio != null) {
- if (stopOnPodcastEnds) {
+ MediaService.duration ?? Duration(seconds: this.studio.duration);
+ if (event.compareTo(duration) > 0 && this.nextStudio != null) {
+ if (this.stopOnPodcastEnds) {
MediaService.resetAudioPlayer();
return;
}
- getStudioDetails(nextStudio!.id, isForward: true);
+ this.getStudioDetails(this.nextStudio!.id, isForward: true);
}
});
}
@@ -199,7 +205,7 @@ class StudioDetailsState extends CoreProvier {
notifyListeners();
}
- Future handleTracking({
+ Future handleTracking({
required int id,
bool sendRequest = true,
}) async {
@@ -207,6 +213,7 @@ class StudioDetailsState extends CoreProvier {
_trackingTimerCounter = 0;
_trackingTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
_trackingTimerCounter++;
+ notifyListeners();
});
return;
}
@@ -224,6 +231,7 @@ class StudioDetailsState extends CoreProvier {
@override
void dispose() {
_trackingTimer?.cancel();
+ _positionSubscription?.cancel();
super.dispose();
}
}
\ No newline at end of file
diff --git a/lib/views/story_viewer/story_viewer_page.dart b/lib/views/story_viewer/story_viewer_page.dart
index f9ff67f..22db765 100644
--- a/lib/views/story_viewer/story_viewer_page.dart
+++ b/lib/views/story_viewer/story_viewer_page.dart
@@ -3,11 +3,10 @@ import 'package:didvan/models/story_model.dart';
import 'package:didvan/services/story_service.dart';
import 'package:didvan/utils/date_time.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
+import 'package:didvan/views/widgets/shimmer_placeholder.dart';
import 'package:flutter/material.dart';
-import 'package:flutter_svg/flutter_svg.dart';
import 'package:video_player/video_player.dart';
-// Main PageViewer to swipe between users
class StoryViewerPage extends StatefulWidget {
final List stories;
final int tappedIndex;
@@ -137,7 +136,7 @@ class _UserStoryViewerState extends State
_animationController.duration =
_videoController!.value.duration;
_videoController!.play();
- // _animationController.forward();
+ _animationController.forward();
} else {
print(
"Video failed to initialize or has zero duration. Skipping.");
@@ -232,6 +231,7 @@ class _UserStoryViewerState extends State
switch (story.media) {
case MediaType.image:
return CachedNetworkImage(
+ placeholder: (context, url) => const ShimmerPlaceholder(),
imageUrl: story.url,
fit: BoxFit.cover,
width: double.infinity,
diff --git a/lib/views/widgets/ai_banner.dart b/lib/views/widgets/ai_banner.dart
index 063087a..c05e796 100644
--- a/lib/views/widgets/ai_banner.dart
+++ b/lib/views/widgets/ai_banner.dart
@@ -1,7 +1,5 @@
import 'package:didvan/services/webview.dart';
import 'package:flutter/material.dart';
-import 'package:flutter/widgets.dart';
-import 'package:flutter_svg/svg.dart';
class AiBanner extends StatelessWidget {
const AiBanner({
diff --git a/lib/views/widgets/didvan/text_field.dart b/lib/views/widgets/didvan/text_field.dart
index 78c3a86..f3ffb1e 100644
--- a/lib/views/widgets/didvan/text_field.dart
+++ b/lib/views/widgets/didvan/text_field.dart
@@ -107,48 +107,51 @@ class _DidvanTextFieldState extends State {
textDirection: val.text.startsWithEnglish()
? TextDirection.ltr
: TextDirection.rtl,
- child: TextFormField(
- inputFormatters: [
- if (!widget.acceptSpace)
- FilteringTextInputFormatter.allow(
- RegExp("[0-9a-zA-Z\u0600-\u06FF]")),
- ],
- autofocus: widget.autoFocus,
- obscureText: _hideContent,
- textAlign: widget.textAlign ?? TextAlign.start,
- keyboardType: widget.textInputType,
- textInputAction: widget.textInputAction,
- focusNode: _focusNode,
- controller: _controller,
- onFieldSubmitted: widget.onSubmitted,
- onChanged: _onChanged,
- validator: _validator,
- maxLines: _hideContent ? 1 : widget.maxLine,
- minLines: widget.minLine,
- maxLength: widget.maxLength,
- obscuringCharacter: '*',
- buildCounter: widget.showLen
- ? null
- : (context,
- {required currentLength,
- required isFocused,
- required maxLength}) =>
- const SizedBox(),
- style: (widget.isSmall
- ? Theme.of(context).textTheme.bodySmall!
- : Theme.of(context).textTheme.bodyMedium!)
- .copyWith(
- fontFamily: DesignConfig.fontFamily.padRight(3)),
- decoration: InputDecoration(
- suffixIcon: _suffixBuilder(),
- enabled: widget.enabled,
- border: InputBorder.none,
- hintText: widget.hintText,
- errorStyle: const TextStyle(height: 0.01),
- hintStyle: (widget.isSmall
+ child: Padding(
+ padding: const EdgeInsets.fromLTRB(8,8,0,8),
+ child: TextFormField(
+ inputFormatters: [
+ if (!widget.acceptSpace)
+ FilteringTextInputFormatter.allow(
+ RegExp("[0-9a-zA-Z\u0600-\u06FF]")),
+ ],
+ autofocus: widget.autoFocus,
+ obscureText: _hideContent,
+ textAlign: widget.textAlign ?? TextAlign.start,
+ keyboardType: widget.textInputType,
+ textInputAction: widget.textInputAction,
+ focusNode: _focusNode,
+ controller: _controller,
+ onFieldSubmitted: widget.onSubmitted,
+ onChanged: _onChanged,
+ validator: _validator,
+ maxLines: _hideContent ? 1 : widget.maxLine,
+ minLines: widget.minLine,
+ maxLength: widget.maxLength,
+ obscuringCharacter: '*',
+ buildCounter: widget.showLen
+ ? null
+ : (context,
+ {required currentLength,
+ required isFocused,
+ required maxLength}) =>
+ const SizedBox(),
+ style: (widget.isSmall
? Theme.of(context).textTheme.bodySmall!
: Theme.of(context).textTheme.bodyMedium!)
- .copyWith(color: Theme.of(context).colorScheme.hint),
+ .copyWith(
+ fontFamily: DesignConfig.fontFamily.padRight(3)),
+ decoration: InputDecoration(
+ suffixIcon: _suffixBuilder(),
+ enabled: widget.enabled,
+ border: InputBorder.none,
+ hintText: widget.hintText,
+ errorStyle: const TextStyle(height: 0.01),
+ hintStyle: (widget.isSmall
+ ? Theme.of(context).textTheme.bodySmall!
+ : Theme.of(context).textTheme.bodyMedium!)
+ .copyWith(color: Theme.of(context).colorScheme.hint),
+ ),
),
),
);
diff --git a/lib/views/widgets/hoshan_app_bar.dart b/lib/views/widgets/hoshan_app_bar.dart
index 5f563d2..2ebf2ec 100644
--- a/lib/views/widgets/hoshan_app_bar.dart
+++ b/lib/views/widgets/hoshan_app_bar.dart
@@ -4,10 +4,8 @@ import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/routes/routes.dart';
import 'package:didvan/views/ai/ai_state.dart';
-import 'package:didvan/views/ai/bot_assistants_state.dart';
import 'package:didvan/views/widgets/didvan/icon_button.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
-import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
@@ -65,24 +63,24 @@ class HoshanAppBar extends StatelessWidget implements PreferredSizeWidget {
Navigator.pushNamed(context, Routes.info);
}),
if (withActions)
- Stack(
- children: [
- DidvanIconButton(
- icon: DidvanIcons.ai_regular,
- size: 32,
- onPressed: () {
- context.read().getMyAssissmant();
+ // Stack(
+ // children: [
+ // DidvanIconButton(
+ // icon: DidvanIcons.ai_regular,
+ // size: 32,
+ // onPressed: () {
+ // context.read().getMyAssissmant();
- Navigator.pushNamed(context, Routes.botAssistants);
- },
- ),
- Icon(
- CupertinoIcons.plus,
- color: Theme.of(context).colorScheme.primary,
- size: 16,
- )
- ],
- ),
+ // Navigator.pushNamed(context, Routes.botAssistants);
+ // },
+ // ),
+ // Icon(
+ // CupertinoIcons.plus,
+ // color: Theme.of(context).colorScheme.primary,
+ // size: 16,
+ // )
+ // ],
+ // ),
if (context.watch().page != 0 || !withActions)
Transform.rotate(
angle: 180 * pi / 180,
diff --git a/lib/views/widgets/video/primary_controls.dart b/lib/views/widgets/video/primary_controls.dart
index 7686acd..b4ce37c 100644
--- a/lib/views/widgets/video/primary_controls.dart
+++ b/lib/views/widgets/video/primary_controls.dart
@@ -351,21 +351,25 @@ class _PrimaryControlsState extends State {
Duration duration =
chewieController.videoPlayerController.value.duration;
+ if (duration.inSeconds == 0) {
+ return const SizedBox(); // Ya namayesh-e yek loading bar
+ }
+
+ double maxValue = duration.inMilliseconds.toDouble();
+ double currentValue = p.inMilliseconds.toDouble();
+
return Column(
children: [
SliderTheme(
data: SliderThemeData(
trackHeight: 2,
- // thumbColor: Colors.transparent,
overlayShape: SliderComponentShape.noOverlay,
thumbShape: const RoundSliderThumbShape(
- // elevation: 0,
- // pressedElevation: 0,
enabledThumbRadius: 8)),
child: Slider(
min: 0,
- max: duration.inMilliseconds.toDouble(),
- value: p.inMilliseconds.toDouble(),
+ max: maxValue,
+ value: currentValue.clamp(0.0, maxValue), // Estefade az clamp
onChanged: (value) async {
await chewieController.pause();
position.value = Duration(milliseconds: value.round());
diff --git a/pubspec.lock b/pubspec.lock
index a5052d2..63a7aff 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -1101,6 +1101,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "8.0.1"
+ pin_input_text_field:
+ dependency: transitive
+ description:
+ name: pin_input_text_field
+ sha256: f45683032283d30b670ec343781660655e3e1953438b281a0bc6e2d358486236
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.5.2"
platform:
dependency: transitive
description:
@@ -1237,6 +1245,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.4"
+ shimmer:
+ dependency: "direct main"
+ description:
+ name: shimmer
+ sha256: "5f88c883a22e9f9f299e5ba0e4f7e6054857224976a5d9f839d4ebdc94a14ac9"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.0"
skeleton_text:
dependency: "direct main"
description:
@@ -1250,6 +1266,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
+ sms_autofill:
+ dependency: "direct main"
+ description:
+ name: sms_autofill
+ sha256: c65836abe9c1f62ce411bb78d5546a09ece4297558070b1bd871db1db283aaf9
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.1"
source_span:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index fc543d0..ca657b5 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -110,6 +110,8 @@ dependencies:
package_info_plus: ^8.3.0
flutter_local_notifications: ^19.1.0
flutter_inappwebview: ^6.1.5
+ sms_autofill: ^2.4.1
+ shimmer: ^3.0.0
# fading_edge_scrollview: ^4.1.1
dev_dependencies:
flutter_test: