swot category added
This commit is contained in:
parent
399374530e
commit
75241cf93e
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 5.7 KiB |
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="29" height="29" viewBox="0 0 29 29" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M20.7429 26.6555C22.0896 26.5238 23.4338 26.3678 24.7749 26.1875C25.2102 26.1304 25.6142 25.9303 25.9234 25.6186C26.2326 25.3069 26.4294 24.9012 26.4829 24.4655C26.6429 23.1795 26.8009 21.8415 26.9289 20.4715M9.01291 2.28748C7.66619 2.41911 6.32197 2.57513 4.98091 2.75548C4.54552 2.81201 4.14127 3.01165 3.83173 3.32301C3.52218 3.63436 3.3249 4.03977 3.27091 4.47548C3.10196 5.80513 2.95328 7.13729 2.82491 8.47148M20.7429 2.28748C22.1229 2.41948 23.4729 2.58348 24.7749 2.75548C25.2099 2.81242 25.6137 3.01225 25.9229 3.32356C26.232 3.63488 26.429 4.04006 26.4829 4.47548C26.6429 5.76348 26.8009 7.10148 26.9289 8.47148M9.01291 26.6555C7.66632 26.5226 6.32212 26.3666 4.98091 26.1875C4.54522 26.1308 4.14075 25.9309 3.83117 25.6192C3.52159 25.3074 3.32449 24.9015 3.27091 24.4655C3.10198 23.1365 2.9533 21.805 2.82491 20.4715M14.8769 10.7955V8.22548M14.8769 10.7955C16.4509 10.7955 18.0849 10.7955 19.5349 10.9835C20.1429 11.0593 20.7095 11.3317 21.1485 11.7591C21.5875 12.1866 21.8749 12.7457 21.9669 13.3515C22.0849 14.1575 22.0849 14.9755 22.0849 16.3675C22.0849 17.7615 22.0849 18.5795 21.9649 19.3835C21.8731 19.9887 21.5863 20.5473 21.1481 20.9747C20.7099 21.4021 20.1442 21.6748 19.5369 21.7515C18.0869 21.9415 16.4529 21.9415 14.8789 21.9415C13.3069 21.9415 11.6729 21.9415 10.2229 21.7515C9.6149 21.6756 9.0483 21.4033 8.60931 20.9758C8.17031 20.5484 7.88294 19.9892 7.79091 19.3835C7.67291 18.5795 7.67291 17.7615 7.67291 16.3675C7.67291 14.9735 7.67291 14.1575 7.79091 13.3515C7.88294 12.7457 8.17031 12.1866 8.60931 11.7591C9.0483 11.3317 9.6149 11.0593 10.2229 10.9835C11.6729 10.7955 13.3049 10.7955 14.8769 10.7955ZM17.4709 16.7555V15.9795M12.2769 16.7555V15.9795M14.8769 8.19948C16.1089 8.19948 16.8029 7.50548 16.8029 6.27348C16.8029 5.04148 16.1089 4.35148 14.8769 4.35148C13.6449 4.35148 12.9529 5.04548 12.9529 6.27548C12.9529 7.50548 13.6469 8.19948 14.8769 8.19948Z" stroke="#195D80" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
|
|
@ -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<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
||||
|
||||
// @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<void> _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<Didvan> 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<Didvan> 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<Didvan> with WidgetsBindingObserver {
|
|||
ChangeNotifierProvider<AiState>(
|
||||
create: (context) => AiState(),
|
||||
),
|
||||
ChangeNotifierProvider<AiChatState>(
|
||||
create: (context) => AiChatState(),
|
||||
),
|
||||
ChangeNotifierProvider<BotAssistantsState>(
|
||||
create: (context) => BotAssistantsState(),
|
||||
),
|
||||
// ChangeNotifierProvider<StoryViewerState>(
|
||||
// create: (context) => StoryViewerState(),
|
||||
// ),
|
||||
],
|
||||
child: Consumer<ThemeProvider>(
|
||||
builder: (context, themeProvider, child) => Container(
|
||||
|
|
@ -223,7 +195,6 @@ class _DidvanState extends State<Didvan> 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<Didvan> with WidgetsBindingObserver {
|
|||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<StoryItem> 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Ai> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
context.read<AiState>().getTools();
|
||||
@override
|
||||
_AiState createState() => _AiState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: [
|
||||
Consumer<AiState>(
|
||||
builder: (BuildContext context, state, Widget? child) {
|
||||
switch (state.page) {
|
||||
case 1:
|
||||
return const ToolScreen();
|
||||
case 0:
|
||||
default:
|
||||
return Consumer<HistoryAiChatState>(
|
||||
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<AiState>(
|
||||
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<AiState>()
|
||||
.getTools();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
class _AiState extends State<Ai> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
context.read<AiState>().getTools();
|
||||
context.read<HistoryAiChatState>().getBots();
|
||||
}
|
||||
|
||||
return const SizedBox();
|
||||
},
|
||||
)
|
||||
],
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: [
|
||||
Consumer<AiState>(
|
||||
builder: (BuildContext context, state, Widget? child) {
|
||||
switch (state.page) {
|
||||
case 1:
|
||||
return const ToolScreen();
|
||||
case 0:
|
||||
default:
|
||||
return Consumer<HistoryAiChatState>(
|
||||
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<AiState>(
|
||||
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<AiState>()
|
||||
.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<HistoryAiChatState>();
|
||||
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<AiState>().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<HistoryAiChatState>(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),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
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,
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -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<AiChatPage> {
|
|||
final GlobalKey<ScaffoldState> scaffKey = GlobalKey<ScaffoldState>();
|
||||
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<AiChatState>();
|
||||
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<AiChatState>();
|
||||
|
|
@ -59,6 +88,8 @@ class _AiChatPageState extends State<AiChatPage> {
|
|||
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<AiChatPage> {
|
|||
() => focusNode.requestFocus(),
|
||||
));
|
||||
} else {
|
||||
state.appState = AppState.idle;
|
||||
Future.delayed(
|
||||
const Duration(
|
||||
milliseconds: 100,
|
||||
|
|
@ -103,145 +135,141 @@ class _AiChatPageState extends State<AiChatPage> {
|
|||
},
|
||||
child: Consumer<AiChatState>(
|
||||
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<AiChatState>(
|
||||
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<AiChatPage> {
|
|||
: 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<AiChatPage> {
|
|||
.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<HistoryAiChatState>()
|
||||
// .bots;
|
||||
// return <PopupMenuEntry>[
|
||||
// ...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<HistoryAiChatState>()
|
||||
.bots;
|
||||
return <PopupMenuEntry>[
|
||||
...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<AiChatPage> {
|
|||
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<AiChatPage> {
|
|||
: 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<AiChatPage> {
|
|||
child: Image.file(file.main)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>? 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<HistoryAiChatPage> {
|
|||
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<HistoryAiChatPage> {
|
|||
builder: (context, state, child) {
|
||||
return SliverStateHandler(
|
||||
state: state,
|
||||
centerEmptyState: false,
|
||||
emptyState: EmptyState(
|
||||
asset: Assets.emptyResult,
|
||||
title: 'لیست خالی است',
|
||||
|
|
@ -106,8 +107,6 @@ class _HistoryAiChatPageState extends State<HistoryAiChatPage> {
|
|||
: 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<HistoryAiChatPage> {
|
|||
},
|
||||
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<HistoryAiChatPage> {
|
|||
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<HistoryAiChatPage> {
|
|||
chat.assistantsName ??
|
||||
chat.bot!.name.toString(),
|
||||
fontWeight: FontWeight.bold,
|
||||
// fontSize: 18,
|
||||
),
|
||||
DidvanText(
|
||||
DateTimeUtils.momentGenerator(
|
||||
|
|
@ -377,8 +370,6 @@ class _HistoryAiChatPageState extends State<HistoryAiChatPage> {
|
|||
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<HistoryAiChatPage> {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Widget openAiListBtn(BuildContext context) {
|
||||
// final watch = context.watch<HistoryAiChatState>();
|
||||
// final state = context.read<HistoryAiChatState>();
|
||||
// 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 {
|
|||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -297,11 +297,12 @@ class _AiMessageBarState extends State<AiMessageBar> {
|
|||
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,
|
||||
|
|
|
|||
|
|
@ -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<HoshanDrawer> {
|
||||
@override
|
||||
void initState() {
|
||||
initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
final historyState = context.read<HistoryAiChatState>();
|
||||
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<HoshanDrawer> {
|
|||
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<HoshanDrawer> {
|
|||
onRetry: () => state.getChats())
|
||||
],
|
||||
)),
|
||||
|
||||
// SizedBox(
|
||||
// height: 12,
|
||||
// ),
|
||||
// Text('نمایش قدیمیترها')
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
@ -315,11 +300,19 @@ class _HoshanDrawerState extends State<HoshanDrawer> {
|
|||
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<HoshanDrawer> {
|
|||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<AiState>()
|
||||
.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 ?? "انتخابی"}' موجود نیست.")),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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<AiState>();
|
||||
|
||||
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<AiState>();
|
||||
|
||||
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<AiState>();
|
||||
|
||||
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<AiState>();
|
||||
|
||||
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<AiSectionPage> createState() => _AiSectionPageState();
|
||||
}
|
||||
|
||||
class _AiSectionPageState extends State<AiSectionPage>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late TabController _tabController;
|
||||
class _AiSectionPageState extends State<AiSectionPage> {
|
||||
int _currentTabIndex = 2;
|
||||
final GlobalKey<ScaffoldState> _aiSectionScaffoldKey =
|
||||
GlobalKey<ScaffoldState>();
|
||||
|
||||
final List<Widget> _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<HistoryAiChatState>();
|
||||
if (historyAiChatState.bots.isEmpty) {
|
||||
|
|
@ -131,28 +132,64 @@ class _AiSectionPageState extends State<AiSectionPage>
|
|||
}
|
||||
|
||||
final aiState = context.read<AiState>();
|
||||
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>();
|
||||
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<AiState>();
|
||||
|
||||
return Scaffold(
|
||||
key: _aiSectionScaffoldKey,
|
||||
appBar: HoshanAppBar(
|
||||
onBack: () {
|
||||
final aiState = context.read<AiState>();
|
||||
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<AiSectionPage>
|
|||
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,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<AiState>();
|
||||
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<AiState>();
|
||||
// نکته: طبق کد شما، تب جستجو (اندیس ۳) ویجت تحلیل نمودار را نمایش میدهد
|
||||
// که از ابزار اندیس ۱ استفاده میکند.
|
||||
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<AiState>();
|
||||
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(
|
||||
|
|
|
|||
|
|
@ -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<String?> login(UserProvider userProvider) async {
|
||||
|
|
|
|||
|
|
@ -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<Verification> {
|
|||
);
|
||||
_handleTimer();
|
||||
super.initState();
|
||||
_listenForSms();
|
||||
}
|
||||
|
||||
Future<void> _listenForSms() async {
|
||||
if (kDebugMode) {
|
||||
print("<<<<< در حال تلاش برای دریافت امضای برنامه >>>>>");
|
||||
}
|
||||
|
||||
final appSignature = await SmsAutoFill().getAppSignature;
|
||||
|
||||
if (kDebugMode) {
|
||||
print("App Signature: $appSignature");
|
||||
}
|
||||
|
||||
await SmsAutoFill().listenForCode();
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -63,13 +63,11 @@ class _HomeState extends State<Home>
|
|||
),
|
||||
],
|
||||
),
|
||||
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<Home>
|
|||
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<Home>
|
|||
if (widget.showDialogs ?? false) {
|
||||
_showDialog(context);
|
||||
}
|
||||
// if (!kIsWeb) {
|
||||
// NotificationService.startListeningNotificationEvents();
|
||||
// }
|
||||
|
||||
final state = context.read<HomeState>();
|
||||
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<HistoryAiChatState>();
|
||||
|
||||
state.getBots();
|
||||
// با هر بار ورود به تب هوشان، لیست چتها ریست میشود
|
||||
final historyState = context.read<HistoryAiChatState>();
|
||||
historyState.chats.clear();
|
||||
historyState.archivedChats.clear();
|
||||
historyState.update(); // برای اطمینان از بهروزرسانی UI
|
||||
historyState.getBots();
|
||||
}
|
||||
});
|
||||
if (!kIsWeb) {
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -33,11 +33,9 @@ class MainPageState extends CoreProvier {
|
|||
Future<void> _fetchStories() async {
|
||||
try {
|
||||
stories = await StoryService.getStories();
|
||||
// [اضافه شود] تعداد استوری های دریافت شده را چاپ کنید
|
||||
print("Fetched ${stories.length} stories.");
|
||||
} catch (e) {
|
||||
stories = [];
|
||||
// [اضافه شود] خطای رخ داده را چاپ کنید
|
||||
debugPrint("Could not fetch stories: $e");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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<UserStories> 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,
|
||||
|
|
|
|||
|
|
@ -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<SwotItemCard> {
|
||||
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<SwotItemCard> {
|
|||
);
|
||||
},
|
||||
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<SwotItemCard> {
|
|||
),
|
||||
),
|
||||
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<SwotItemCard> {
|
|||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
|
|
@ -128,24 +145,25 @@ class _SwotItemCardState extends State<SwotItemCard> {
|
|||
)
|
||||
],
|
||||
),
|
||||
// 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<SwotItemCard> {
|
|||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<StudioDetails> {
|
||||
// ignore: unused_field
|
||||
int _currentlyPlayingId = 0;
|
||||
late VideoPlayerController _videoPlayerController;
|
||||
VideoPlayerController? _videoPlayerController;
|
||||
ChewieController? _chewieController;
|
||||
|
||||
@override
|
||||
|
|
@ -40,26 +40,9 @@ class _StudioDetailsState extends State<StudioDetails> {
|
|||
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<StudioDetails> {
|
|||
() => Navigator.of(context).pushNamed(
|
||||
Routes.mentions,
|
||||
arguments: {
|
||||
'id': state.studio.id,
|
||||
'id': context.read<StudioDetailsState>().studio.id,
|
||||
'type': 'studio',
|
||||
'title': state.studio.title,
|
||||
'title': context.read<StudioDetailsState>().studio.title,
|
||||
},
|
||||
),
|
||||
);
|
||||
|
|
@ -82,99 +65,135 @@ class _StudioDetailsState extends State<StudioDetails> {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> _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<StudioDetailsState>(
|
||||
builder: (context, state, child) => StateHandler<StudioDetailsState>(
|
||||
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<StudioDetailsState>(
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,11 +18,14 @@ class StudioDetailsState extends CoreProvier {
|
|||
StudioRequestArgs? args;
|
||||
StudioRequestArgs? podcastArgs;
|
||||
final List<int> 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<void> _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<void> handleTracking({
|
||||
Future<void> 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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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<UserStories> stories;
|
||||
final int tappedIndex;
|
||||
|
|
@ -137,7 +136,7 @@ class _UserStoryViewerState extends State<UserStoryViewer>
|
|||
_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<UserStoryViewer>
|
|||
switch (story.media) {
|
||||
case MediaType.image:
|
||||
return CachedNetworkImage(
|
||||
placeholder: (context, url) => const ShimmerPlaceholder(),
|
||||
imageUrl: story.url,
|
||||
fit: BoxFit.cover,
|
||||
width: double.infinity,
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -107,48 +107,51 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
|
|||
textDirection: val.text.startsWithEnglish()
|
||||
? TextDirection.ltr
|
||||
: TextDirection.rtl,
|
||||
child: TextFormField(
|
||||
inputFormatters: <TextInputFormatter>[
|
||||
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: <TextInputFormatter>[
|
||||
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),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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<BotAssistantsState>().getMyAssissmant();
|
||||
// Stack(
|
||||
// children: [
|
||||
// DidvanIconButton(
|
||||
// icon: DidvanIcons.ai_regular,
|
||||
// size: 32,
|
||||
// onPressed: () {
|
||||
// context.read<BotAssistantsState>().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<AiState>().page != 0 || !withActions)
|
||||
Transform.rotate(
|
||||
angle: 180 * pi / 180,
|
||||
|
|
|
|||
|
|
@ -351,21 +351,25 @@ class _PrimaryControlsState extends State<PrimaryControls> {
|
|||
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());
|
||||
|
|
|
|||
24
pubspec.lock
24
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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Reference in New Issue