From 5f02802ad19c1f1891a6360f3c39bce7da8ba81b Mon Sep 17 00:00:00 2001 From: mohamadmahdi jebeli Date: Sat, 12 Jul 2025 15:30:37 +0330 Subject: [PATCH] fixed story index bug --- android/app/src/main/AndroidManifest.xml | 1 + lib/models/home_page_content/banner.dart | 1 - lib/models/home_page_content/content.dart | 6 +- lib/models/slider_data.dart | 9 +- lib/routes/route_generator.dart | 3 + lib/services/ai/ai_api_service.dart | 2 +- lib/services/media/media.dart | 128 ++++++++--------- lib/services/network/request_helper.dart | 4 +- lib/services/note_service.dart | 3 + lib/services/swot_service.dart | 2 + lib/services/webview.dart | 2 + lib/views/ai/ai.dart | 1 + lib/views/ai/ai_chat_page.dart | 53 +++---- lib/views/ai/ai_chat_state.dart | 2 +- lib/views/ai/widgets/hoshan_drawer.dart | 1 - lib/views/ai_section/ai_section_page.dart | 10 +- lib/views/direct/direct_state.dart | 15 +- lib/views/direct/widgets/message_box.dart | 136 ++++++++++-------- .../home/bookmarks/bookmark_service.dart | 5 +- lib/views/home/bookmarks/bookmarks.dart | 1 + lib/views/home/home.dart | 2 + lib/views/home/main/main_page.dart | 3 - lib/views/home/main/main_page_state.dart | 9 +- lib/views/home/main/widgets/bookmark.dart | 2 + .../home/main/widgets/bookmarked_icon.dart | 1 + .../home/main/widgets/story_section.dart | 5 +- .../home/main/widgets/swot_bookmark.dart | 1 + lib/views/home/widgets/categories.dart | 1 + .../studio_details/studio_details_state.dart | 4 +- lib/views/podcasts/widgets/slider.dart | 11 +- lib/views/story_viewer/story_viewer_page.dart | 24 +++- lib/views/widgets/audio/player_navbar.dart | 4 +- lib/views/widgets/hoshan_app_bar.dart | 37 ++--- pubspec.lock | 26 +++- pubspec.yaml | 4 +- 35 files changed, 296 insertions(+), 223 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 1ba4137..791d5a1 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -17,6 +17,7 @@ android:icon="@mipmap/ic_launcher" android:label="Didvan" android:requestLegacyExternalStorage="true" + android:usesCleartextTraffic="true"> json) { return MainPageBannerType( - // fix if it null image: json['image'] ?? '', link: json['link'], ); diff --git a/lib/models/home_page_content/content.dart b/lib/models/home_page_content/content.dart index 0a47576..e32a62a 100644 --- a/lib/models/home_page_content/content.dart +++ b/lib/models/home_page_content/content.dart @@ -1,9 +1,11 @@ + class MainPageContentType { final int id; final String title; final String image; final String link; bool marked; + bool isViewed; final List subtitles; final int? duration; @@ -13,6 +15,7 @@ class MainPageContentType { required this.image, required this.link, required this.marked, + required this.isViewed, required this.subtitles, this.duration, }); @@ -24,7 +27,8 @@ class MainPageContentType { image: json['image'], link: json['link'], marked: json['marked'], + isViewed: json['isViewed'] ?? false, subtitles: List.from(json['subtitles']), duration: json['duration'], ); -} +} \ No newline at end of file diff --git a/lib/models/slider_data.dart b/lib/models/slider_data.dart index c6ff0ed..7a78d8e 100644 --- a/lib/models/slider_data.dart +++ b/lib/models/slider_data.dart @@ -1,14 +1,16 @@ + class SliderData { final int id; final String title; final String image; final String link; - + final bool isViewed; const SliderData({ required this.id, required this.title, required this.image, required this.link, + required this.isViewed, }); factory SliderData.fromJson(Map json) => SliderData( @@ -16,11 +18,14 @@ class SliderData { title: json['title'], image: json['image'], link: json['link'], + isViewed: json['isViewed'] ?? false, ); Map toJson() => { 'id': id, 'title': title, 'image': image, + 'link': link, + 'isViewed': isViewed, }; -} +} \ No newline at end of file diff --git a/lib/routes/route_generator.dart b/lib/routes/route_generator.dart index 7ab73a4..b328d00 100644 --- a/lib/routes/route_generator.dart +++ b/lib/routes/route_generator.dart @@ -1,3 +1,5 @@ +// ignore_for_file: avoid_print + import 'package:didvan/models/ai/ai_chat_args.dart'; import 'package:didvan/models/story_model.dart'; import 'package:didvan/views/ai/ai_chat_page.dart'; @@ -494,6 +496,7 @@ class RouteGenerator { textScaler: const TextScaler.linear(1.0), ), child: Container( + // ignore: deprecated_member_use color: Theme.of(context).colorScheme.background, alignment: Alignment.center, child: AspectRatio(aspectRatio: 9 / 16, child: page), diff --git a/lib/services/ai/ai_api_service.dart b/lib/services/ai/ai_api_service.dart index 0bd80bb..2e2837c 100644 --- a/lib/services/ai/ai_api_service.dart +++ b/lib/services/ai/ai_api_service.dart @@ -1,4 +1,4 @@ -// ignore_for_file: depend_on_referenced_packages, avoid_web_libraries_in_flutter +// ignore_for_file: depend_on_referenced_packages, avoid_web_libraries_in_flutter, avoid_print import 'dart:async'; diff --git a/lib/services/media/media.dart b/lib/services/media/media.dart index 2f41c32..6e61877 100644 --- a/lib/services/media/media.dart +++ b/lib/services/media/media.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:device_info_plus/device_info_plus.dart'; import 'package:didvan/constants/assets.dart'; import 'package:didvan/models/requests/studio.dart'; import 'package:didvan/models/studio_details_data.dart'; @@ -9,7 +10,6 @@ import 'package:didvan/services/network/request.dart'; import 'package:didvan/services/network/request_helper.dart'; import 'package:didvan/services/storage/storage.dart'; import 'package:didvan/utils/action_sheet.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_downloader/flutter_downloader.dart'; import 'package:get/get.dart'; @@ -90,17 +90,7 @@ class MediaService { } } await audioPlayer.play(); - // await audioPlayer.open( - // audio, - // showNotification: !isVoiceMessage, - // notificationSettings: NotificationSettings( - // customStopAction: (_) => resetAudioPlayer(), - // customNextAction: (_) => onTrackChanged?.call(true), - // customPrevAction: (_) => onTrackChanged?.call(false), - // ), - // ); } catch (e) { - // resetAudioPlayer(); // rethrow; } } @@ -133,7 +123,6 @@ class MediaService { return result; } catch (e) { e.printError(info: 'Pick PDF Fail'); - // navigatorKey.currentState!.pop(); return null; } } @@ -143,30 +132,11 @@ class MediaService { return await FilePicker.platform .pickFiles( type: FileType.any, - // allowedExtensions: [ - // 'pdf', - // 'doc', - // 'docx', - // 'xls', - // 'xlsx', - // 'ppt', - // 'pptx', - // 'txt', - // 'mp3', - // 'wav', - // 'aac', - // 'ogg', - // 'flac' - // ], // You can specify allowed extensions if needed allowMultiple: true, - // Note: The maxFiles parameter is not directly supported by FilePicker. - // You will need to handle the limit after selection if necessary. ) .then((result) { if (result != null && result.files.length > 3) { - // Handle the case where the selected files exceed the max limit - // You can show an error message or return null - return null; // or show a message to the user + return null; } return result; }); @@ -189,47 +159,75 @@ class MediaService { } static Future downloadFile(String url, {final String? name}) async { + debugPrint("Attempting to download file from URL: $url"); final basename = name ?? p.basename(url).split('?accessToken=').first; - Directory? dir; - try { - if (Platform.isIOS) { - dir = await getApplicationDocumentsDirectory(); // for iOS - } else { - dir = Directory('/storage/emulated/0/Download/'); // for android - if (!await dir.exists()) dir = (await getExternalStorageDirectory())!; - } - } catch (err) { - if (kDebugMode) { - print("Cannot get download folder path $err"); - } - } - String path = "${dir?.path}${Platform.isIOS ? '/' : ''}"; - final status = await Permission.storage.request(); - if (status.isGranted) { - try { - await FlutterDownloader.enqueue( - url: url, - savedDir: path, - fileName: basename, - showNotification: true, - openFileFromNotification: true, - ); - } catch (e) { - if (kDebugMode) { - print("Exception$e"); + + PermissionStatus status; + if (Platform.isAndroid) { + final androidInfo = await DeviceInfoPlugin().androidInfo; + if (androidInfo.version.sdkInt >= 33) { + debugPrint("Android 13+ detected. Requesting Photos permission."); + status = await Permission.photos.request(); + } else { + debugPrint("Older Android version detected. Requesting Storage permission."); + status = await Permission.storage.request(); } - return null; - } + } else if (Platform.isIOS) { + debugPrint("iOS detected. Requesting Photos permission."); + status = await Permission.photos.request(); } else { - return null; + status = PermissionStatus.granted; } - return path; + debugPrint("Permission status after request: $status"); + + if (status.isGranted) { + Directory? dir; + try { + if (Platform.isIOS) { + dir = await getApplicationDocumentsDirectory(); + } else { + dir = await getExternalStorageDirectory(); + } + + if (dir == null) { + debugPrint("Error: Could not determine download directory."); + return null; + } + + final path = dir.path; + debugPrint("Download directory determined: $path"); + + final taskId = await FlutterDownloader.enqueue( + url: url, + savedDir: path, + fileName: basename, + showNotification: true, + openFileFromNotification: true, + saveInPublicStorage: true, + ); + debugPrint("Download successfully enqueued with taskId: $taskId"); + return path; + + } catch (e) { + debugPrint("Error during download process: $e"); + return null; + } + } else if (status.isPermanentlyDenied) { + debugPrint("Storage permission is permanently denied. Opening app settings."); + await openAppSettings(); + return null; + } else { + debugPrint("Storage permission was denied."); + return null; + } } + static String downloadFileFromWeb(String url) { + final filename = url.split('/').last.split('?').first; html.AnchorElement anchorElement = html.AnchorElement(href: url); - anchorElement.download = url; + anchorElement.download = filename; anchorElement.click(); return anchorElement.pathname!; } @@ -249,4 +247,4 @@ class MediaService { hasDismissButton: false, )); } -} +} \ No newline at end of file diff --git a/lib/services/network/request_helper.dart b/lib/services/network/request_helper.dart index 1f35e4c..7664f52 100644 --- a/lib/services/network/request_helper.dart +++ b/lib/services/network/request_helper.dart @@ -6,7 +6,7 @@ import 'package:didvan/models/requests/studio.dart'; class RequestHelper { static const String baseUrl = 'https://api.didvan.app'; - static const String baseUrl2 = 'http://opportunity-threat.didvan.com'; + static const String baseUrl2 = 'https://opportunity-threat.didvan.com'; static const String storiesV1 = '$baseUrl2/api/v1/stories'; static const String storyActivity = '$baseUrl2/api/v1/stories/activity'; static const String _baseUserUrl = '$baseUrl/user'; @@ -20,7 +20,7 @@ class RequestHelper { static const String _baseHomeUrl = '$baseUrl/home'; static const String _baseNewStats = '$baseUrl/home/statistic'; static const String _baseNewStatsSearch = '$baseUrl/home/statistic/search'; - static const String checkHasPassword = '$_baseUserUrl/checkHasPassword'; + static const String checkHasPassword = '$_baseUserUrl/checkHasPassword'; static const String mainPageContent = _baseHomeUrl; static String searchAll({ diff --git a/lib/services/note_service.dart b/lib/services/note_service.dart index fe4e046..36a0d44 100644 --- a/lib/services/note_service.dart +++ b/lib/services/note_service.dart @@ -1,8 +1,11 @@ +// ignore_for_file: avoid_print + import 'dart:convert'; import 'package:didvan/models/note.dart'; import 'package:didvan/services/network/request.dart'; import 'package:didvan/services/network/request_helper.dart'; +// ignore: library_prefixes import 'package:http/http.dart' as RequestServices; class NoteService { diff --git a/lib/services/swot_service.dart b/lib/services/swot_service.dart index cbe282a..019c603 100644 --- a/lib/services/swot_service.dart +++ b/lib/services/swot_service.dart @@ -1,3 +1,5 @@ +// ignore_for_file: avoid_print + import 'dart:convert'; import 'package:didvan/models/home_page_content/swot.dart'; import 'package:didvan/services/network/request.dart'; diff --git a/lib/services/webview.dart b/lib/services/webview.dart index 9a6600b..37ed897 100644 --- a/lib/services/webview.dart +++ b/lib/services/webview.dart @@ -1,3 +1,5 @@ +// ignore_for_file: avoid_print + import 'package:flutter/services.dart'; class NativeWebViewLauncher { diff --git a/lib/views/ai/ai.dart b/lib/views/ai/ai.dart index 8e02014..3b638c0 100644 --- a/lib/views/ai/ai.dart +++ b/lib/views/ai/ai.dart @@ -20,6 +20,7 @@ const Ai({Key? key}) : super(key: key); @override + // ignore: library_private_types_in_public_api _AiState createState() => _AiState(); } diff --git a/lib/views/ai/ai_chat_page.dart b/lib/views/ai/ai_chat_page.dart index 95d40cf..d28741c 100644 --- a/lib/views/ai/ai_chat_page.dart +++ b/lib/views/ai/ai_chat_page.dart @@ -1,8 +1,5 @@ -// 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; @@ -599,27 +596,26 @@ class _AiChatPageState extends State { ), ), if (message.file != null && !kIsWeb) - !Platform.isIOS - ? Padding( - padding: const EdgeInsets.all(8.0), - child: InkWell( - onTap: () async { - final url = - '${RequestHelper.baseUrl + message.file.toString()}?accessToken=${RequestService.token}'; - await MediaService.downloadFile( - url, - name: message.fileName); - }, - child: Icon( - DidvanIcons.download_solid, - size: 18, - color: Theme.of(context) - .colorScheme - .focusedBorder, - ), - ), - ) - : const SizedBox.shrink(), + Padding( + padding: const EdgeInsets.all(8.0), + child: InkWell( + onTap: () async { + debugPrint( + "Download button tapped on iOS"); + final url = + '${RequestHelper.baseUrl + message.file.toString()}?accessToken=${RequestService.token}'; + await MediaService.downloadFile(url, + name: message.fileName); + }, + child: Icon( + DidvanIcons.download_solid, + size: 18, + color: Theme.of(context) + .colorScheme + .focusedBorder, + ), + ), + ), if (message.error != null && message.error!) Padding( padding: const EdgeInsets.all(8.0), @@ -645,14 +641,7 @@ class _AiChatPageState extends State { ), ), ), - if (state.messages[mIndex].prompts[index] - .text != - null || - (state.messages[mIndex].prompts[index] - .text != - null && - state.messages[mIndex].prompts[index] - .text!.isNotEmpty)) + if (message.text != null && message.text!.isNotEmpty && (file == null || !file.isImage())) Padding( padding: const EdgeInsets.all(8.0), child: InkWell( diff --git a/lib/views/ai/ai_chat_state.dart b/lib/views/ai/ai_chat_state.dart index 8379cb1..533209f 100644 --- a/lib/views/ai/ai_chat_state.dart +++ b/lib/views/ai/ai_chat_state.dart @@ -1,4 +1,4 @@ -// ignore_for_file: body_might_complete_normally_catch_error +// ignore_for_file: body_might_complete_normally_catch_error, avoid_print import 'dart:async'; import 'dart:convert'; diff --git a/lib/views/ai/widgets/hoshan_drawer.dart b/lib/views/ai/widgets/hoshan_drawer.dart index fcc5a14..08ee9e7 100644 --- a/lib/views/ai/widgets/hoshan_drawer.dart +++ b/lib/views/ai/widgets/hoshan_drawer.dart @@ -9,7 +9,6 @@ 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'; diff --git a/lib/views/ai_section/ai_section_page.dart b/lib/views/ai_section/ai_section_page.dart index b884466..3b8531c 100644 --- a/lib/views/ai_section/ai_section_page.dart +++ b/lib/views/ai_section/ai_section_page.dart @@ -1,4 +1,3 @@ -// 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'; @@ -185,15 +184,8 @@ class _AiSectionPageState extends State { key: _aiSectionScaffoldKey, appBar: HoshanAppBar( onBack: () { - if (aiState.isChatting) { - aiState.endChat(); - setState(() { - _currentTabIndex = 2; - }); - } else { Navigator.of(context).pop(); - } - }, + }, withActions: true, ), drawer: HoshanDrawer(scaffKey: _aiSectionScaffoldKey), diff --git a/lib/views/direct/direct_state.dart b/lib/views/direct/direct_state.dart index ca0ca28..7dcf139 100644 --- a/lib/views/direct/direct_state.dart +++ b/lib/views/direct/direct_state.dart @@ -11,6 +11,7 @@ import 'package:didvan/services/media/voice.dart'; import 'package:didvan/services/network/request.dart'; import 'package:didvan/services/network/request_helper.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_sound/public/flutter_sound_player.dart'; import 'package:flutter_sound/public/flutter_sound_recorder.dart'; import 'package:flutter_sound_platform_interface/flutter_sound_platform_interface.dart'; @@ -24,7 +25,7 @@ class DirectState extends CoreProvier { final Map> dailyMessages = {}; final List deletionQueue = []; - String? text; + final TextEditingController textController = TextEditingController(); NewsAttachment? replyNews; RadarAttachment? replyRadar; int? audioDuration; @@ -104,6 +105,7 @@ class DirectState extends CoreProvier { @override void dispose() { + textController.dispose(); super.dispose(); mPlayer!.closePlayer(); mPlayer = null; @@ -172,7 +174,7 @@ class DirectState extends CoreProvier { } Future startRecording() async { - text = null; + textController.text.isEmpty; // await _recorder.hasPermission(); record(); @@ -228,13 +230,14 @@ class DirectState extends CoreProvier { } Future sendMessage() async { - if ((text == null || text!.isEmpty) && path == null) return; + + if ((textController.text.isEmpty) && path == null) return; VoiceService.audioPlayer.stop(); final body = {}; - if (text != null) { - body.addAll({'text': text}); + if (textController.text.isNotEmpty) { + body.addAll({'text': textController.text}); } if (replyRadar != null) { @@ -253,7 +256,7 @@ class DirectState extends CoreProvier { body.addAll({'duration': countTimer.value.inSeconds.toString()}); } - text = null; + textController.clear(); notifyListeners(); diff --git a/lib/views/direct/widgets/message_box.dart b/lib/views/direct/widgets/message_box.dart index 6e6cf19..3705908 100644 --- a/lib/views/direct/widgets/message_box.dart +++ b/lib/views/direct/widgets/message_box.dart @@ -1,3 +1,4 @@ + import 'package:didvan/config/design_config.dart'; import 'package:didvan/config/theme_data.dart'; import 'package:didvan/constants/app_icons.dart'; @@ -9,54 +10,60 @@ import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -class MessageBox extends StatelessWidget { +class MessageBox extends StatefulWidget { const MessageBox({Key? key}) : super(key: key); + @override + State createState() => _MessageBoxState(); +} + +class _MessageBoxState extends State { @override Widget build(BuildContext context) { return Column( children: [ Consumer( - builder: (context, state, child) => state.replyRadar != null || - state.replyNews != null - ? _MessageBoxContainer( - isMessage: false, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const DidvanText( - 'لینک به مطلب:', + builder: (context, state, child) => + state.replyRadar != null || state.replyNews != null + ? _MessageBoxContainer( + isMessage: false, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const DidvanText( + 'لینک به مطلب:', + ), + DidvanText( + state.replyRadar != null + ? state.replyRadar!.title + : state.replyNews!.title, + overflow: TextOverflow.ellipsis, + maxLines: 1, + color: + Theme.of(context).colorScheme.primary, + ), + ], ), - DidvanText( - state.replyRadar != null - ? state.replyRadar!.title - : state.replyNews!.title, - overflow: TextOverflow.ellipsis, - maxLines: 1, - color: Theme.of(context).colorScheme.primary, - ), - ], - ), + ), + DidvanIconButton( + icon: DidvanIcons.close_regular, + gestureSize: 24, + onPressed: () { + state.replyRadar = null; + state.replyNews = null; + state.update(); + }, + ), + ], ), - DidvanIconButton( - icon: DidvanIcons.close_regular, - gestureSize: 24, - onPressed: () { - state.replyRadar = null; - state.replyNews = null; - state.update(); - }, - ), - ], - ), - ), - ) - : const SizedBox(), + ), + ) + : const SizedBox(), ), _MessageBoxContainer( isMessage: true, @@ -111,7 +118,21 @@ class _Typing extends StatefulWidget { } class _TypingState extends State<_Typing> { - final _formKey = GlobalKey(); + @override + void initState() { + super.initState(); + context.read().textController.addListener(_rebuild); + } + + @override + void dispose() { + context.read().textController.removeListener(_rebuild); + super.dispose(); + } + + void _rebuild() { + setState(() {}); + } @override Widget build(BuildContext context) { @@ -126,13 +147,11 @@ class _TypingState extends State<_Typing> { scale: animation, child: child, ), - child: state.text != null && state.text!.isNotEmpty + child: state.textController.text.isNotEmpty ? DidvanIconButton( icon: DidvanIcons.send_solid, onPressed: () async { await state.sendMessage(); - state.update(); - _formKey.currentState!.reset(); }, size: 32, color: Theme.of(context).colorScheme.focusedBorder, @@ -147,23 +166,17 @@ class _TypingState extends State<_Typing> { ), Expanded( flex: 15, - child: Form( - key: _formKey, - child: TextFormField( - textInputAction: TextInputAction.send, - style: Theme.of(context).textTheme.bodyMedium, - decoration: InputDecoration( - border: InputBorder.none, - hintText: 'بنویسید یا پیام صوتی بگذارید...', - hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith( - color: Theme.of(context).colorScheme.disabledText), - ), - onChanged: (value) { - if (value.length <= 1) { - setState(() {}); - } - state.text = value; - }, + child: TextFormField( + controller: state.textController, + textInputAction: TextInputAction.send, + style: Theme.of(context).textTheme.bodyMedium, + decoration: InputDecoration( + border: InputBorder.none, + hintText: 'بنویسید یا پیام صوتی بگذارید...', + hintStyle: Theme.of(context) + .textTheme + .bodySmall! + .copyWith(color: Theme.of(context).colorScheme.disabledText), ), ), ), @@ -227,7 +240,6 @@ class _RecordChecking extends StatelessWidget { child: AudioWave( file: state.path!, totalDuration: state.countTimer.value, - // deleteClidk: () => state.deleteRecordedFile, ), ), ), @@ -245,4 +257,4 @@ class _RecordChecking extends StatelessWidget { ], ); } -} +} \ No newline at end of file diff --git a/lib/views/home/bookmarks/bookmark_service.dart b/lib/views/home/bookmarks/bookmark_service.dart index 5f00e8c..234ef29 100644 --- a/lib/views/home/bookmarks/bookmark_service.dart +++ b/lib/views/home/bookmarks/bookmark_service.dart @@ -1,9 +1,10 @@ +// ignore_for_file: avoid_print + import 'dart:convert'; import 'package:didvan/models/home_page_content/swot.dart'; import 'package:didvan/services/network/request.dart'; import 'package:didvan/services/network/request_helper.dart'; import 'package:http/http.dart' as http; -import 'package:http/http.dart' as RequestServicess; class BookmarkService { static Future> fetchBookmarks() async { @@ -69,7 +70,7 @@ class BookmarkService { } static Future> fetchBookmarkedSwotItems() async { - final postIds = await fetchBookmarks(); // استفاده از همان لیست بوکمارک‌ها + final postIds = await fetchBookmarks(); final List items = []; for (final postId in postIds) { diff --git a/lib/views/home/bookmarks/bookmarks.dart b/lib/views/home/bookmarks/bookmarks.dart index 0f324a8..e01b323 100644 --- a/lib/views/home/bookmarks/bookmarks.dart +++ b/lib/views/home/bookmarks/bookmarks.dart @@ -44,6 +44,7 @@ class _BookmarksState extends State { } + // ignore: unused_element void _onSearchChanged(String value) { final state = context.read(); if (value.length < 3 && value.isNotEmpty) { diff --git a/lib/views/home/home.dart b/lib/views/home/home.dart index 33a7093..4442229 100644 --- a/lib/views/home/home.dart +++ b/lib/views/home/home.dart @@ -78,6 +78,7 @@ class _HomeState extends State ) .then((value) => ActionSheetUtils(context).openDialog( data: ActionSheetData( + // ignore: deprecated_member_use backgroundColor: Theme.of(context).colorScheme.background, isBackgroundDropBlur: true, content: Stack( @@ -208,6 +209,7 @@ class _HomeState extends State scaffKey: homeScaffKey, ) : null, + // ignore: deprecated_member_use body: WillPopScope( onWillPop: () async { if (context.read().tabController.index == 0) { diff --git a/lib/views/home/main/main_page.dart b/lib/views/home/main/main_page.dart index 97d4994..720aa24 100644 --- a/lib/views/home/main/main_page.dart +++ b/lib/views/home/main/main_page.dart @@ -3,7 +3,6 @@ import 'package:didvan/constants/app_icons.dart'; import 'package:didvan/main.dart'; import 'package:didvan/models/home_page_content/home_page_list.dart'; import 'package:didvan/models/home_page_content/swot.dart'; -import 'package:didvan/services/swot_service.dart'; import 'package:didvan/routes/routes.dart'; import 'package:didvan/services/app_initalizer.dart'; import 'package:didvan/views/home/main/main_page_state.dart'; @@ -48,10 +47,8 @@ class _MainPageState extends State { children: [ if (state.stories.isNotEmpty) StorySection(stories: state.stories), const SizedBox(height: 12), - // Main page content const MainPageMainContent(), - // START: MODIFIED SECTION Builder(builder: (context) { final List pageContent = []; if (state.content != null && state.content!.lists.isNotEmpty) { diff --git a/lib/views/home/main/main_page_state.dart b/lib/views/home/main/main_page_state.dart index 022eeda..95e1f4a 100644 --- a/lib/views/home/main/main_page_state.dart +++ b/lib/views/home/main/main_page_state.dart @@ -1,5 +1,6 @@ import 'package:didvan/main.dart'; import 'package:didvan/models/enums.dart'; +import 'package:didvan/models/home_page_content/content.dart'; import 'package:didvan/models/home_page_content/home_page_content.dart'; import 'package:didvan/models/home_page_content/swot.dart'; import 'package:didvan/models/requests/infography.dart'; @@ -33,7 +34,12 @@ class MainPageState extends CoreProvier { } } - Future _getSwotItems() async { // این متد را اضافه کنید + int getStoryStartIndex(List stories) { + final firstUnreadIndex = stories.indexWhere((story) => !story.isViewed); + return firstUnreadIndex != -1 ? firstUnreadIndex : 0; +} + + Future _getSwotItems() async { try { swotItems = await SwotService.fetchSwotItems(); } catch (e) { @@ -44,6 +50,7 @@ class MainPageState extends CoreProvier { Future _fetchStories() async { try { stories = await StoryService.getStories(); + // ignore: avoid_print print("Fetched ${stories.length} stories."); } catch (e) { stories = []; diff --git a/lib/views/home/main/widgets/bookmark.dart b/lib/views/home/main/widgets/bookmark.dart index 4819a47..64e7958 100644 --- a/lib/views/home/main/widgets/bookmark.dart +++ b/lib/views/home/main/widgets/bookmark.dart @@ -1,3 +1,5 @@ +// ignore_for_file: avoid_print + import 'package:didvan/config/theme_data.dart'; import 'package:didvan/constants/app_icons.dart'; import 'package:didvan/views/home/bookmarks/bookmark_service.dart'; diff --git a/lib/views/home/main/widgets/bookmarked_icon.dart b/lib/views/home/main/widgets/bookmarked_icon.dart index 40b021b..f7ec19a 100644 --- a/lib/views/home/main/widgets/bookmarked_icon.dart +++ b/lib/views/home/main/widgets/bookmarked_icon.dart @@ -80,6 +80,7 @@ class _BookmarkedIconState extends State { widget.onBookmarkChanged?.call(newBookmarkStatus); } } catch (e) { + // ignore: avoid_print print("Error toggling bookmark for post ${widget.postId}: $e"); } finally { if (mounted) { diff --git a/lib/views/home/main/widgets/story_section.dart b/lib/views/home/main/widgets/story_section.dart index 4f8a909..e6d84a5 100644 --- a/lib/views/home/main/widgets/story_section.dart +++ b/lib/views/home/main/widgets/story_section.dart @@ -23,11 +23,14 @@ class StorySection extends StatelessWidget { child: _StoryCircle( userStories: userStories, onTap: () { + bool allStoriesViewed = stories.every((userStories) => + userStories.stories.every((story) => story.isViewed.value)); + Navigator.of(context).pushNamed( Routes.storyViewer, arguments: { 'stories': stories, - 'tappedIndex': index, + 'tappedIndex': allStoriesViewed ? 0 : index, }, ); }, diff --git a/lib/views/home/main/widgets/swot_bookmark.dart b/lib/views/home/main/widgets/swot_bookmark.dart index 240d658..9eba511 100644 --- a/lib/views/home/main/widgets/swot_bookmark.dart +++ b/lib/views/home/main/widgets/swot_bookmark.dart @@ -57,6 +57,7 @@ class _SwotBookmark extends State { } void saveOrUpdateNote(String content) async { + // ignore: avoid_print print('Processing note for PostId: ${widget.item.id}, Content: $content'); setState(() { isLoading = true; diff --git a/lib/views/home/widgets/categories.dart b/lib/views/home/widgets/categories.dart index 4ecec20..77e9c22 100644 --- a/lib/views/home/widgets/categories.dart +++ b/lib/views/home/widgets/categories.dart @@ -19,6 +19,7 @@ class MainCategories extends StatelessWidget { '$link?accessToken=${RequestService.token}', mode: LaunchMode.inAppWebView, ); + // ignore: avoid_print print("your goddamn token is :${RequestService.token}"); } else if (link.startsWith('tab-')) { final state = context.read(); diff --git a/lib/views/podcasts/studio_details/studio_details_state.dart b/lib/views/podcasts/studio_details/studio_details_state.dart index be39e35..408dd94 100644 --- a/lib/views/podcasts/studio_details/studio_details_state.dart +++ b/lib/views/podcasts/studio_details/studio_details_state.dart @@ -1,3 +1,5 @@ +// ignore_for_file: unnecessary_this + import 'dart:async'; import 'package:didvan/models/enums.dart'; @@ -22,9 +24,7 @@ class StudioDetailsState extends CoreProvier { int _trackingTimerCounter = 0; Timer? _trackingTimer; - // BEGIN: ADD THIS LINE StreamSubscription? _positionSubscription; - // END: ADD THIS LINE int _selectedDetailsIndex = 0; Timer? timer; diff --git a/lib/views/podcasts/widgets/slider.dart b/lib/views/podcasts/widgets/slider.dart index d7cd82b..f07436a 100644 --- a/lib/views/podcasts/widgets/slider.dart +++ b/lib/views/podcasts/widgets/slider.dart @@ -41,11 +41,18 @@ class _StudioSliderState extends State { padding: const EdgeInsets.symmetric(horizontal: 4), child: GestureDetector( onTap: () { + final firstUnreadIndex = + state.sliders.indexWhere((story) => !story.isViewed); + + final startId = (firstUnreadIndex == -1) + ? state.sliders.first.id + : state.sliders[firstUnreadIndex].id; + if (state.videosSelected) { Navigator.of(context) .pushNamed(Routes.studioDetails, arguments: { 'onMarkChanged': state.changeMark, - 'id': state.sliders[i].id, + 'id': startId, 'args': const StudioRequestArgs(page: 0, type: 'video'), 'hasUnmarkConfirmation': false, @@ -54,7 +61,7 @@ class _StudioSliderState extends State { return; } context.read().getStudioDetails( - state.sliders[i].id, + startId, args: const StudioRequestArgs( page: 0, type: 'podcast', diff --git a/lib/views/story_viewer/story_viewer_page.dart b/lib/views/story_viewer/story_viewer_page.dart index c34f404..e02d221 100644 --- a/lib/views/story_viewer/story_viewer_page.dart +++ b/lib/views/story_viewer/story_viewer_page.dart @@ -1,8 +1,8 @@ +// ignore_for_file: avoid_print + import 'package:cached_network_image/cached_network_image.dart'; 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:video_player/video_player.dart'; @@ -92,7 +92,24 @@ class _UserStoryViewerState extends State void initState() { super.initState(); _animationController = AnimationController(vsync: this); - _loadStory(story: widget.userStories.stories.first); + + final allStoriesInGroupViewed = + widget.userStories.stories.every((story) => story.isViewed.value); + + if (allStoriesInGroupViewed) { + for (final story in widget.userStories.stories) { + story.isViewed.value = false; + } + } + + _currentStoryIndex = + widget.userStories.stories.indexWhere((story) => !story.isViewed.value); + + if (_currentStoryIndex == -1) { + _currentStoryIndex = 0; + } + + _loadStory(story: widget.userStories.stories[_currentStoryIndex]); _animationController.addStatusListener((status) { if (status == AnimationStatus.completed) { @@ -314,6 +331,7 @@ class _AnimatedBar extends StatelessWidget { decoration: BoxDecoration( color: position < currentIndex ? Colors.white + // ignore: deprecated_member_use : Colors.white.withOpacity(0.5), border: Border.all(color: Colors.black26, width: 0.8), borderRadius: BorderRadius.circular(30.0), diff --git a/lib/views/widgets/audio/player_navbar.dart b/lib/views/widgets/audio/player_navbar.dart index 223ca5b..d61e749 100644 --- a/lib/views/widgets/audio/player_navbar.dart +++ b/lib/views/widgets/audio/player_navbar.dart @@ -1,3 +1,5 @@ +// ignore_for_file: unused_element + import 'package:didvan/config/theme_data.dart'; import 'package:expandable_bottom_sheet/expandable_bottom_sheet.dart'; import 'package:flutter/material.dart'; @@ -7,8 +9,6 @@ import 'package:provider/provider.dart'; import '../../../config/design_config.dart'; import '../../../constants/app_icons.dart'; import '../../../models/enums.dart'; -import '../../../models/requests/radar.dart'; -import '../../../routes/routes.dart'; import '../../../services/media/media.dart'; import '../../../utils/action_sheet.dart'; import '../../podcasts/podcasts_state.dart'; diff --git a/lib/views/widgets/hoshan_app_bar.dart b/lib/views/widgets/hoshan_app_bar.dart index 2ebf2ec..6b1e2f7 100644 --- a/lib/views/widgets/hoshan_app_bar.dart +++ b/lib/views/widgets/hoshan_app_bar.dart @@ -1,13 +1,8 @@ -import 'dart:math'; - 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/widgets/didvan/icon_button.dart'; import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; class HoshanAppBar extends StatelessWidget implements PreferredSizeWidget { final Function()? onBack; @@ -55,14 +50,14 @@ class HoshanAppBar extends StatelessWidget implements PreferredSizeWidget { ), Row( children: [ - if (withInfo) - DidvanIconButton( - icon: DidvanIcons.info_circle_light, - size: 32, - onPressed: () { - Navigator.pushNamed(context, Routes.info); - }), - if (withActions) + // if (withInfo) + // DidvanIconButton( + // icon: DidvanIcons.info_circle_light, + // size: 32, + // onPressed: () { + // Navigator.pushNamed(context, Routes.info); + // }), + // if (withActions) // Stack( // children: [ // DidvanIconButton( @@ -81,15 +76,13 @@ class HoshanAppBar extends StatelessWidget implements PreferredSizeWidget { // ) // ], // ), - if (context.watch().page != 0 || !withActions) - Transform.rotate( - angle: 180 * pi / 180, - child: DidvanIconButton( - icon: DidvanIcons.back_light, - size: 32, - onPressed: () => onBack?.call(), - ), + if (withInfo) + DidvanIconButton( + icon: DidvanIcons.angle_left_light, + size: 32, + onPressed: () => onBack?.call(), ), + ], ) ], @@ -98,4 +91,4 @@ class HoshanAppBar extends StatelessWidget implements PreferredSizeWidget { @override Size get preferredSize => const Size(double.infinity, 144); -} +} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 63a7aff..a079ef9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -201,6 +201,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.11" + device_info_plus: + dependency: "direct main" + description: + name: device_info_plus + sha256: "98f28b42168cc509abc92f88518882fd58061ea372d7999aecc424345c7bff6a" + url: "https://pub.dev" + source: hosted + version: "11.5.0" + device_info_plus_platform_interface: + dependency: transitive + description: + name: device_info_plus_platform_interface + sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f + url: "https://pub.dev" + source: hosted + version: "7.0.3" equatable: dependency: transitive description: @@ -1650,6 +1666,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.12.0" + win32_registry: + dependency: transitive + description: + name: win32_registry + sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae" + url: "https://pub.dev" + source: hosted + version: "2.1.0" xdg_directories: dependency: transitive description: @@ -1668,4 +1692,4 @@ packages: version: "6.5.0" sdks: dart: ">=3.7.0 <4.0.0" - flutter: ">=3.27.0" + flutter: ">=3.29.0" diff --git a/pubspec.yaml b/pubspec.yaml index ca657b5..08b2548 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 3.3.8+3380 +version: 4.0.1+4380 environment: sdk: ">=2.19.0 <3.0.0" @@ -112,6 +112,8 @@ dependencies: flutter_inappwebview: ^6.1.5 sms_autofill: ^2.4.1 shimmer: ^3.0.0 + device_info_plus: ^11.5.0 + # image_gallery_saver: ^2.0.3 # fading_edge_scrollview: ^4.1.1 dev_dependencies: flutter_test: