From c88324da81f5749a0b612d3dceda4ad2215d317b Mon Sep 17 00:00:00 2001 From: mohamadmahdi jebeli Date: Mon, 14 Jul 2025 15:46:38 +0330 Subject: [PATCH] fixed news --- lib/main.dart | 182 ++++++++---------- lib/services/network/request.dart | 13 +- .../news/news_details/news_details_state.dart | 39 ++-- lib/views/splash/splash.dart | 59 ++---- 4 files changed, 131 insertions(+), 162 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 3948322..0f9185f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,3 +1,5 @@ +// lib/main.dart + // ignore_for_file: deprecated_member_use import 'dart:async'; @@ -7,6 +9,7 @@ import 'package:bot_toast/bot_toast.dart'; import 'package:didvan/config/theme_data.dart'; import 'package:didvan/firebase_options.dart'; import 'package:didvan/models/notification_message.dart'; +import 'package:didvan/models/requests/news.dart'; import 'package:didvan/providers/media.dart'; import 'package:didvan/providers/theme.dart'; import 'package:didvan/providers/user.dart'; @@ -32,56 +35,54 @@ import 'package:home_widget/home_widget.dart'; import 'package:provider/provider.dart'; import 'package:flutter_downloader/flutter_downloader.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; - -// پکیج جدید برای Deep Linking import 'package:app_links/app_links.dart'; final GlobalKey navigatorKey = GlobalKey(); - -// متغیر استاتیک برای نگهداری لینک اولیه Uri? initialURI; @pragma('vm:entry-point') Future _backgroundCallbackHomeWidget(Uri? uri) async { if (uri != null) { - await HomeWidget.saveWidgetData("uri", uri.host); + await HomeWidget.saveWidgetData("uri", uri.host); } } void main() async { - WidgetsFlutterBinding.ensureInitialized(); - try { - if (!kIsWeb) { - HomeWidget.registerBackgroundCallback(_backgroundCallbackHomeWidget); - HomeWidget.registerInteractivityCallback(_backgroundCallbackHomeWidget); - await NotificationService.initializeNotification(); + runZonedGuarded( + () async { + WidgetsFlutterBinding.ensureInitialized(); try { - if (Platform.isAndroid) { - await FlutterDownloader.initialize( - debug: true, - ignoreSsl: true - ); + if (!kIsWeb) { + HomeWidget.registerBackgroundCallback(_backgroundCallbackHomeWidget); + HomeWidget.registerInteractivityCallback(_backgroundCallbackHomeWidget); + await NotificationService.initializeNotification(); + try { + if (Platform.isAndroid) { + await FlutterDownloader.initialize(debug: true, ignoreSsl: true); + } + } catch (e) { + e.printError(); + } } + + await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); + await FirebaseApi().initNotification(); } catch (e) { - e.printError(); + debugPrint(e.toString()); } - } - await Firebase.initializeApp( - options: DefaultFirebaseOptions.currentPlatform); - await FirebaseApi().initNotification(); - } catch (e) { - debugPrint(e.toString()); - } - - await SentryFlutter.init( - (options) { - options.dsn = - 'https://a4cfcaa7d67471240d295c25c968d91d@o4508585857384448.ingest.de.sentry.io/4508585886548048'; - options.tracesSampleRate = 1.0; - options.profilesSampleRate = 1.0; + await SentryFlutter.init( + (options) { + options.dsn = 'https://a4cfcaa7d67471240d295c25c968d91d@o4508585857384448.ingest.de.sentry.io/4508585886548048'; + options.tracesSampleRate = 1.0; + options.profilesSampleRate = 1.0; + }, + appRunner: () => runApp(const Didvan()), + ); + }, + (error, stack) { + Sentry.captureException(error, stackTrace: stack); }, - appRunner: () => runApp(const Didvan()), ); } @@ -100,55 +101,40 @@ class _DidvanState extends State with WidgetsBindingObserver { void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); - // مقداردهی اولیه و گوش دادن به لینک‌ها در اینجا انجام می‌شود _initDeepLinks(); } - + @override void dispose() { WidgetsBinding.instance.removeObserver(this); - _linkSubscription?.cancel(); // لغو کردن subscription + _linkSubscription?.cancel(); if (MediaService.currentPodcast != null) { MediaService.audioPlayer.dispose(); } super.dispose(); } - - /// منطق جدید برای مدیریت لینک‌ها با app_links + Future _initDeepLinks() async { _appLinks = AppLinks(); - - // لینک اولیه را فقط در متغیر ذخیره می‌کنیم initialURI = await _appLinks.getInitialLink(); - - // به لینک‌های جدید زمانی که اپلیکیشن باز است گوش می‌دهیم _linkSubscription = _appLinks.uriLinkStream.listen((uri) { _navigateTo(uri); }); } - - /// تابع کمکی برای ناوبری + void _navigateTo(Uri uri) { if (mounted) { String path = uri.path; - print("path: $path, uri: $uri"); - - if (path.contains("news")) { - final regex = RegExp(r'^/news/(\d+)$'); - final match = regex.firstMatch(path); - - if (match != null) { - final id = match.group(1); // This will be '1234' as a string - print('Extracted ID: $id'); - navigatorKey.currentState?.pushNamed(Routes.newsDetails, arguments: { 'id': int.parse(id!) ,'hasUnmarkConfirmation':true, 'isForward': true }); - } else { - print('No match found'); + if (path.startsWith('/news/')) { + final id = path.split('/news/').last; + if (id.isNotEmpty) { + navigatorKey.currentState?.pushNamed( + Routes.newsDetails, + arguments: {'id': int.parse(id), 'args': const NewsRequestArgs(page: 0)}, + ); } - - } else { - print("no fragments identified. opening home path, uri: $uri"); - navigatorKey.currentState?.pushNamed(path); + navigatorKey.currentState?.pushNamed(path); } } } @@ -158,11 +144,9 @@ class _DidvanState extends State with WidgetsBindingObserver { if (!kIsWeb) { if (state == AppLifecycleState.resumed) { var r = await HomeWidget.getWidgetData("cRoute", defaultValue: ''); - if (r!.toString() != Routes.splash) { - await HomeWidgetRepository.decideWhereToGo(); - + if (r.toString() != Routes.splash) { + await HomeWidgetRepository.decideWhereToGo(); NotificationMessage? data = HomeWidgetRepository.data; - if (data != null) { await HomeWidgetRepository.decideWhereToGoNotif(); } @@ -190,43 +174,43 @@ class _DidvanState extends State with WidgetsBindingObserver { color: Theme.of(context).colorScheme.surface, child: SafeArea( child: MaterialApp( - scrollBehavior: MyCustomScrollBehavior(), - navigatorKey: navigatorKey, - debugShowCheckedModeBanner: false, - title: 'Didvan', - theme: LightThemeConfig.themeData.copyWith( - bottomSheetTheme: const BottomSheetThemeData( - surfaceTintColor: Colors.transparent, - backgroundColor: Colors.transparent), - textTheme: LightThemeConfig.themeData.textTheme.apply( - fontFamily: themeProvider.fontFamily, - )), - darkTheme: DarkThemeConfig.themeData.copyWith( - bottomSheetTheme: const BottomSheetThemeData( - surfaceTintColor: Colors.transparent, - backgroundColor: Colors.transparent), - textTheme: DarkThemeConfig.themeData.textTheme.apply( - fontFamily: themeProvider.fontFamily, - )), - color: LightThemeConfig.themeData.primaryColor, - themeMode: themeProvider.themeMode, - onGenerateRoute: (settings) => - RouteGenerator.generateRoute(settings), - builder: BotToastInit(), - navigatorObservers: [BotToastNavigatorObserver()], - initialRoute: "/", - localizationsDelegates: const [ - GlobalCupertinoLocalizations.delegate, - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - ], - supportedLocales: const [ - Locale("fa", "IR"), - ], - locale: const Locale("fa", "IR"), - )), + scrollBehavior: MyCustomScrollBehavior(), + navigatorKey: navigatorKey, + debugShowCheckedModeBanner: false, + title: 'Didvan', + theme: LightThemeConfig.themeData.copyWith( + bottomSheetTheme: const BottomSheetThemeData( + surfaceTintColor: Colors.transparent, + backgroundColor: Colors.transparent), + textTheme: LightThemeConfig.themeData.textTheme.apply( + fontFamily: themeProvider.fontFamily, + )), + darkTheme: DarkThemeConfig.themeData.copyWith( + bottomSheetTheme: const BottomSheetThemeData( + surfaceTintColor: Colors.transparent, + backgroundColor: Colors.transparent), + textTheme: DarkThemeConfig.themeData.textTheme.apply( + fontFamily: themeProvider.fontFamily, + )), + color: LightThemeConfig.themeData.primaryColor, + themeMode: themeProvider.themeMode, + onGenerateRoute: (settings) => + RouteGenerator.generateRoute(settings), + builder: BotToastInit(), + navigatorObservers: [BotToastNavigatorObserver()], + initialRoute: "/", + localizationsDelegates: const [ + GlobalCupertinoLocalizations.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ], + supportedLocales: const [ + Locale("fa", "IR"), + ], + locale: const Locale("fa", "IR"), + )), ), ), ); } -} +} \ No newline at end of file diff --git a/lib/services/network/request.dart b/lib/services/network/request.dart index bad60ff..96bd092 100644 --- a/lib/services/network/request.dart +++ b/lib/services/network/request.dart @@ -1,3 +1,5 @@ +// lib/services/network/request.dart + // ignore_for_file: empty_catches import 'dart:convert'; @@ -15,7 +17,7 @@ import 'package:mime/mime.dart'; import 'package:permission_handler/permission_handler.dart'; class RequestService { - static late String token; + static String? token; // Made token nullable int? statusCode; dynamic data(String s) { @@ -48,12 +50,9 @@ class RequestService { }) { if (body != null) _requestBody = body; if (requestHeaders != null) _headers.addAll(requestHeaders); - if (useAutherization) _headers.addAll({'Authorization': 'Bearer $token'}); - // if (kDebugMode) { - // try { - // print('Authorization : Bearer $token'); - // } catch (e) {} - // } + if (useAutherization && token != null) { // Check if token is not null + _headers.addAll({'Authorization': 'Bearer $token'}); + } if (body != null) _requestBody = body; } diff --git a/lib/views/news/news_details/news_details_state.dart b/lib/views/news/news_details/news_details_state.dart index 83300bc..333d2bb 100644 --- a/lib/views/news/news_details/news_details_state.dart +++ b/lib/views/news/news_details/news_details_state.dart @@ -1,3 +1,5 @@ +// lib/views/news/news_details/news_details_state.dart + import 'dart:async'; import 'dart:math'; @@ -8,6 +10,8 @@ import 'package:didvan/models/requests/news.dart'; import 'package:didvan/providers/core.dart'; import 'package:didvan/services/network/request.dart'; import 'package:didvan/services/network/request_helper.dart'; +import 'package:didvan/services/storage/storage.dart'; +import 'package:flutter/material.dart'; class NewsDetailsState extends CoreProvier { final List news = []; @@ -25,26 +29,35 @@ class NewsDetailsState extends CoreProvier { NewsDetailsData get currentNews => news[_currentIndex]!; Future getNewsDetails(int id, {bool? isForward}) async { + debugPrint('requset token ${RequestService.token}'); + // **FIX: Ensure the token is available before making a request.** + if (RequestService.token == null) { + final token = await StorageService.getValue(key: 'token'); + if (token != null) { + RequestService.token = token; + } else { + // If no token, fail gracefully. You might want to navigate + // to the login screen here in a real-world scenario. + appState = AppState.failed; + notifyListeners(); + return; + } + } - print("isForward: $isForward"); - // if (isForward == null) { - // appState = AppState.busy; - // } else { - isFetchingNewItem = true; - notifyListeners(); - // } + isFetchingNewItem = true; + notifyListeners(); + final service = RequestService(RequestHelper.newsDetails(id, args)); await service.httpGet(); - print("making request to news endpoint $id"); _handleTracking(sendRequest: isForward != null); if (service.isSuccess) { - print("success in receiving news detail for id $id"); final result = service.result; final newsItem = NewsDetailsData.fromJson(result['news']); if (args.page == 0) { news.add(newsItem); initialIndex = 0; appState = AppState.idle; + notifyListeners(); // Notify listeners after state change return; } NewsDetailsData? prevNews; @@ -81,12 +94,12 @@ class NewsDetailsState extends CoreProvier { getRelatedContents(); } appState = AppState.idle; + notifyListeners(); // Notify listeners after state change return; } - print("failed to receive news detail for id $id"); - // if (isForward == null) { - // appState = AppState.failed; - // } + + appState = AppState.failed; + notifyListeners(); // Notify listeners on failure } bool exists(NewsDetailsData? newsItem) => diff --git a/lib/views/splash/splash.dart b/lib/views/splash/splash.dart index 8a45489..a700b9b 100644 --- a/lib/views/splash/splash.dart +++ b/lib/views/splash/splash.dart @@ -108,14 +108,11 @@ class _SplashState extends State { print("detected token as $token"); if (token != null) { - print("detected token"); + RequestService.token = token; if (!kIsWeb) { await mediaProvider.getDownloadsList(); } - RequestService.token = token; - - print("fetching user info..."); final result = await userProvider.getUserInfo(); if (!result) { @@ -138,49 +135,25 @@ class _SplashState extends State { await ServerDataProvider.getData(); } - // --- بخش اصلاح شده --- - try { - // Determine destination and arguments based on authentication status - if (token == null) { - // User is not authenticated, go to the authentication screen - print("User not authenticated. Navigating to authentication."); - await navigatorKey.currentState!.pushReplacementNamed( - Routes.authenticaion, - arguments: false, // Pass the expected boolean argument - ); - } else { - // User is authenticated, go to the home screen - print("User authenticated. Navigating to home."); + final String destinationRoute = + token == null ? Routes.authenticaion : Routes.home; + dynamic routeArguments = + token == null ? {'isResetPassword': false} : {'showDialogs': true}; - // Prepare arguments for the home screen - final Map routeArguments = {'showDialogs': true}; - - // If a deep link exists, add it to the arguments - if (initialURI != null) { - print("Deep link found: $initialURI. Adding to arguments."); - routeArguments['deepLinkUri'] = initialURI; - initialURI = null; // Consume the link so it's not used again - } - - // Navigate to the home screen with the correct arguments - await navigatorKey.currentState!.pushReplacementNamed( - Routes.home, - arguments: routeArguments, - ); - } - // --- پایان بخش اصلاح شده --- - - } catch (e) { - print("An error occurred during initialization: $e"); - if (mounted) { - setState(() { - _errorOccured = true; - }); - } + if (destinationRoute == Routes.home && initialURI != null) { + (routeArguments as Map)['deepLinkUri'] = initialURI; + initialURI = null; } + if(destinationRoute == Routes.authenticaion){ + routeArguments = false; + } + + await navigatorKey.currentState!.pushReplacementNamed( + destinationRoute, + arguments: routeArguments, + ); } catch (e) { - print("error in splash screen: $e"); setState(() { _errorOccured = true; });