Compare commits
	
		
			2 Commits
		
	
	
		
			2.2.2+56
			...
			5377161fb0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 5377161fb0 | |||
| 963e538ae5 | 
| @@ -19,6 +19,10 @@ | ||||
|         android:icon="@mipmap/ic_launcher" | ||||
|         android:enableOnBackInvokedCallback="true" | ||||
|         android:requestLegacyExternalStorage="true"> | ||||
|         <meta-data | ||||
|             android:name="flutterEmbedding" | ||||
|             android:value="2" /> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".MainActivity" | ||||
|             android:exported="true" | ||||
|   | ||||
							
								
								
									
										11
									
								
								api/Reader/List News Sources.bru
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								api/Reader/List News Sources.bru
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| meta { | ||||
|   name: List News Sources | ||||
|   type: http | ||||
|   seq: 3 | ||||
| } | ||||
|  | ||||
| get { | ||||
|   url: {{endpoint}}/cgi/re/well-known/sources | ||||
|   body: none | ||||
|   auth: none | ||||
| } | ||||
							
								
								
									
										17
									
								
								api/Reader/List News.bru
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								api/Reader/List News.bru
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| meta { | ||||
|   name: List News | ||||
|   type: http | ||||
|   seq: 2 | ||||
| } | ||||
|  | ||||
| get { | ||||
|   url: {{endpoint}}/cgi/re/news?take=10&offset=0&source=shadiao | ||||
|   body: none | ||||
|   auth: none | ||||
| } | ||||
|  | ||||
| params:query { | ||||
|   take: 10 | ||||
|   offset: 0 | ||||
|   source: shadiao | ||||
| } | ||||
							
								
								
									
										17
									
								
								api/Reader/Trigger Scan News.bru
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								api/Reader/Trigger Scan News.bru
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| meta { | ||||
|   name: Trigger Scan News | ||||
|   type: http | ||||
|   seq: 1 | ||||
| } | ||||
|  | ||||
| post { | ||||
|   url: {{endpoint}}/cgi/re/admin/scan | ||||
|   body: json | ||||
|   auth: inherit | ||||
| } | ||||
|  | ||||
| body:json { | ||||
|   { | ||||
|     "eager": true | ||||
|   } | ||||
| } | ||||
| @@ -17,6 +17,7 @@ | ||||
|   "screenAccountProfileEdit": "Edit Profile", | ||||
|   "screenAbuseReport": "Abuse Reports", | ||||
|   "screenSettings": "Settings", | ||||
|   "screenNews": "News", | ||||
|   "screenAlbum": "Album", | ||||
|   "screenChat": "Chat", | ||||
|   "screenChatManage": "Edit Channel", | ||||
| @@ -558,5 +559,10 @@ | ||||
|   "postCategoryKnowledge": "Knowledge", | ||||
|   "postCategoryLiterature": "Literature", | ||||
|   "postCategoryFunny": "Funny", | ||||
|   "postCategoryUncategorized": "Uncategorized" | ||||
|   "postCategoryUncategorized": "Uncategorized", | ||||
|   "newsAllSources": "All News", | ||||
|   "newsReadingProviderSwap": "Swap", | ||||
|   "newsReadingFromReader": "You're reading from HyperNet.Reader", | ||||
|   "newsReadingFromOriginal": "You're reading the original article", | ||||
|   "newsDisclaimer": "This article is fetched from the Internet, we do not guarantee its authenticity, please judge for yourself. All content in this article belongs to the original author." | ||||
| } | ||||
|   | ||||
| @@ -15,6 +15,7 @@ | ||||
|   "screenAccountProfileEdit": "编辑资料", | ||||
|   "screenAbuseReport": "滥用检举", | ||||
|   "screenSettings": "设置", | ||||
|   "screenNews": "新闻", | ||||
|   "screenAlbum": "相册", | ||||
|   "screenChat": "聊天", | ||||
|   "screenChatManage": "编辑聊天频道", | ||||
| @@ -556,5 +557,10 @@ | ||||
|   "postCategoryKnowledge": "知识", | ||||
|   "postCategoryLiterature": "文学", | ||||
|   "postCategoryFunny": "搞笑", | ||||
|   "postCategoryUncategorized": "未分类" | ||||
|   "postCategoryUncategorized": "未分类", | ||||
|   "newsAllSources": "所有新闻", | ||||
|   "newsReadingProviderSwap": "切换", | ||||
|   "newsReadingFromReader": "你正在从 HyperNet.Reader 阅读文章", | ||||
|   "newsReadingFromOriginal": "你正在阅读原始文章", | ||||
|   "newsDisclaimer": "本文由 HyperNet.Reader 从互联网上获取,我们不担保其内容的真实性,请自行判断。本文章的所有内容版权归原作者所有。" | ||||
| } | ||||
|   | ||||
| @@ -15,6 +15,7 @@ | ||||
|   "screenAccountProfileEdit": "編輯資料", | ||||
|   "screenAbuseReport": "濫用檢舉", | ||||
|   "screenSettings": "設置", | ||||
|   "screenNews": "新聞", | ||||
|   "screenAlbum": "相冊", | ||||
|   "screenChat": "聊天", | ||||
|   "screenChatManage": "編輯聊天頻道", | ||||
| @@ -194,6 +195,10 @@ | ||||
|   "settingsFeatures": "功能", | ||||
|   "settingsNotifyWithHaptic": "新通知時振動", | ||||
|   "settingsNotifyWithHapticDescription": "在應用在前台時收到新通知出現時出發輕量的振動。", | ||||
|   "settingsExpandPostLink": "展開帖子鏈接", | ||||
|   "settingsExpandPostLinkDescription": "在帖子列表中展開顯示帖子中的鏈接。", | ||||
|   "settingsExpandChatLink": "展開聊天鏈接", | ||||
|   "settingsExpandChatLinkDescription": "在聊天信息中展開顯示內容中的鏈接。", | ||||
|   "settingsNetwork": "網絡", | ||||
|   "settingsNetworkServer": "HyperNet 服務器", | ||||
|   "settingsNetworkServerDescription": "設置 HyperNet 服務器地址,選擇我們提供的,或者自己搭建。", | ||||
| @@ -552,5 +557,10 @@ | ||||
|   "postCategoryKnowledge": "知識", | ||||
|   "postCategoryLiterature": "文學", | ||||
|   "postCategoryFunny": "搞笑", | ||||
|   "postCategoryUncategorized": "未分類" | ||||
|   "postCategoryUncategorized": "未分類", | ||||
|   "newsAllSources": "所有新聞", | ||||
|   "newsReadingProviderSwap": "切換", | ||||
|   "newsReadingFromReader": "你正在從 HyperNet.Reader 閲讀文章", | ||||
|   "newsReadingFromOriginal": "你正在閲讀原始文章", | ||||
|   "newsDisclaimer": "本文由 HyperNet.Reader 從互聯網上獲取,我們不擔保其內容的真實性,請自行判斷。本文章的所有內容版權歸原作者所有。" | ||||
| } | ||||
|   | ||||
| @@ -15,6 +15,7 @@ | ||||
|   "screenAccountProfileEdit": "編輯資料", | ||||
|   "screenAbuseReport": "濫用檢舉", | ||||
|   "screenSettings": "設置", | ||||
|   "screenNews": "新聞", | ||||
|   "screenAlbum": "相冊", | ||||
|   "screenChat": "聊天", | ||||
|   "screenChatManage": "編輯聊天頻道", | ||||
| @@ -194,6 +195,10 @@ | ||||
|   "settingsFeatures": "功能", | ||||
|   "settingsNotifyWithHaptic": "新通知時振動", | ||||
|   "settingsNotifyWithHapticDescription": "在應用在前臺時收到新通知出現時出發輕量的振動。", | ||||
|   "settingsExpandPostLink": "展開帖子鏈接", | ||||
|   "settingsExpandPostLinkDescription": "在帖子列表中展開顯示帖子中的鏈接。", | ||||
|   "settingsExpandChatLink": "展開聊天鏈接", | ||||
|   "settingsExpandChatLinkDescription": "在聊天信息中展開顯示內容中的鏈接。", | ||||
|   "settingsNetwork": "網絡", | ||||
|   "settingsNetworkServer": "HyperNet 服務器", | ||||
|   "settingsNetworkServerDescription": "設置 HyperNet 服務器地址,選擇我們提供的,或者自己搭建。", | ||||
| @@ -552,5 +557,10 @@ | ||||
|   "postCategoryKnowledge": "知識", | ||||
|   "postCategoryLiterature": "文學", | ||||
|   "postCategoryFunny": "搞笑", | ||||
|   "postCategoryUncategorized": "未分類" | ||||
|   "postCategoryUncategorized": "未分類", | ||||
|   "newsAllSources": "所有新聞", | ||||
|   "newsReadingProviderSwap": "切換", | ||||
|   "newsReadingFromReader": "你正在從 HyperNet.Reader 閱讀文章", | ||||
|   "newsReadingFromOriginal": "你正在閱讀原始文章", | ||||
|   "newsDisclaimer": "本文由 HyperNet.Reader 從互聯網上獲取,我們不擔保其內容的真實性,請自行判斷。本文章的所有內容版權歸原作者所有。" | ||||
| } | ||||
|   | ||||
| @@ -105,6 +105,13 @@ PODS: | ||||
|   - Flutter (1.0.0) | ||||
|   - flutter_app_update (0.0.1): | ||||
|     - Flutter | ||||
|   - flutter_inappwebview_ios (0.0.1): | ||||
|     - Flutter | ||||
|     - flutter_inappwebview_ios/Core (= 0.0.1) | ||||
|     - OrderedSet (~> 6.0.3) | ||||
|   - flutter_inappwebview_ios/Core (0.0.1): | ||||
|     - Flutter | ||||
|     - OrderedSet (~> 6.0.3) | ||||
|   - flutter_native_splash (2.4.3): | ||||
|     - Flutter | ||||
|   - flutter_udid (0.0.1): | ||||
| @@ -188,6 +195,7 @@ PODS: | ||||
|     - nanopb/encode (= 3.30910.0) | ||||
|   - nanopb/decode (3.30910.0) | ||||
|   - nanopb/encode (3.30910.0) | ||||
|   - OrderedSet (6.0.3) | ||||
|   - package_info_plus (0.4.5): | ||||
|     - Flutter | ||||
|   - pasteboard (0.0.1): | ||||
| @@ -239,6 +247,7 @@ DEPENDENCIES: | ||||
|   - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) | ||||
|   - Flutter (from `Flutter`) | ||||
|   - flutter_app_update (from `.symlinks/plugins/flutter_app_update/ios`) | ||||
|   - flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`) | ||||
|   - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) | ||||
|   - flutter_udid (from `.symlinks/plugins/flutter_udid/ios`) | ||||
|   - flutter_webrtc (from `.symlinks/plugins/flutter_webrtc/ios`) | ||||
| @@ -282,6 +291,7 @@ SPEC REPOS: | ||||
|     - GoogleUtilities | ||||
|     - Kingfisher | ||||
|     - nanopb | ||||
|     - OrderedSet | ||||
|     - PromisesObjC | ||||
|     - SAMKeychain | ||||
|     - SDWebImage | ||||
| @@ -309,6 +319,8 @@ EXTERNAL SOURCES: | ||||
|     :path: Flutter | ||||
|   flutter_app_update: | ||||
|     :path: ".symlinks/plugins/flutter_app_update/ios" | ||||
|   flutter_inappwebview_ios: | ||||
|     :path: ".symlinks/plugins/flutter_inappwebview_ios/ios" | ||||
|   flutter_native_splash: | ||||
|     :path: ".symlinks/plugins/flutter_native_splash/ios" | ||||
|   flutter_udid: | ||||
| @@ -380,6 +392,7 @@ SPEC CHECKSUMS: | ||||
|   FirebaseMessaging: e1aca1fcc23e8b9eddb0e33f375ff90944623021 | ||||
|   Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 | ||||
|   flutter_app_update: 65f61da626cb111d1b24674abc4b01728d7723bc | ||||
|   flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4 | ||||
|   flutter_native_splash: f71420956eb811e6d310720fee915f1d42852e7a | ||||
|   flutter_udid: b2417673f287ee62817a1de3d1643f47b9f508ab | ||||
|   flutter_webrtc: 90260f83024b1b96d239a575ea4e3708e79344d1 | ||||
| @@ -396,6 +409,7 @@ SPEC CHECKSUMS: | ||||
|   media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a | ||||
|   media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e | ||||
|   nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 | ||||
|   OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 | ||||
|   package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4 | ||||
|   pasteboard: 982969ebaa7c78af3e6cc7761e8f5e77565d9ce0 | ||||
|   path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 | ||||
|   | ||||
| @@ -58,6 +58,11 @@ class NavigationProvider extends ChangeNotifier { | ||||
|       screen: 'realm', | ||||
|       label: 'screenRealm', | ||||
|     ), | ||||
|     AppNavDestination( | ||||
|       icon: Icon(Symbols.newspaper, weight: 400, opticalSize: 20), | ||||
|       screen: 'news', | ||||
|       label: 'screenNews', | ||||
|     ), | ||||
|     AppNavDestination( | ||||
|       icon: Icon(Symbols.photo_library, weight: 400, opticalSize: 20), | ||||
|       screen: 'album', | ||||
| @@ -83,8 +88,7 @@ class NavigationProvider extends ChangeNotifier { | ||||
|  | ||||
|   List<AppNavDestination> destinations = []; | ||||
|  | ||||
|   int get pinnedDestinationCount => | ||||
|       destinations.where((ele) => ele.isPinned).length; | ||||
|   int get pinnedDestinationCount => destinations.where((ele) => ele.isPinned).length; | ||||
|  | ||||
|   NavigationProvider() { | ||||
|     buildDestinations(kDefaultPinnedDestination); | ||||
| @@ -113,17 +117,13 @@ class NavigationProvider extends ChangeNotifier { | ||||
|   } | ||||
|  | ||||
|   bool isIndexInRange(int min, int max) { | ||||
|     return _currentIndex != null && | ||||
|         _currentIndex! >= min && | ||||
|         _currentIndex! < max; | ||||
|     return _currentIndex != null && _currentIndex! >= min && _currentIndex! < max; | ||||
|   } | ||||
|  | ||||
|   void autoDetectIndex(GoRouter? state) { | ||||
|     if (state == null) return; | ||||
|     final idx = destinations.indexWhere( | ||||
|       (ele) => | ||||
|           ele.screen == | ||||
|           state.routerDelegate.currentConfiguration.last.route.name, | ||||
|       (ele) => ele.screen == state.routerDelegate.currentConfiguration.last.route.name, | ||||
|     ); | ||||
|     _currentIndex = idx == -1 ? null : idx; | ||||
|     notifyListeners(); | ||||
|   | ||||
| @@ -19,6 +19,8 @@ import 'package:surface/screens/chat/room.dart'; | ||||
| import 'package:surface/screens/explore.dart'; | ||||
| import 'package:surface/screens/friend.dart'; | ||||
| import 'package:surface/screens/home.dart'; | ||||
| import 'package:surface/screens/news/news_detail.dart'; | ||||
| import 'package:surface/screens/news/news_list.dart'; | ||||
| import 'package:surface/screens/notification.dart'; | ||||
| import 'package:surface/screens/post/post_detail.dart'; | ||||
| import 'package:surface/screens/post/post_editor.dart'; | ||||
| @@ -31,7 +33,6 @@ import 'package:surface/screens/settings.dart'; | ||||
| import 'package:surface/screens/sharing.dart'; | ||||
| import 'package:surface/types/post.dart'; | ||||
| import 'package:surface/widgets/about.dart'; | ||||
| import 'package:surface/widgets/navigation/app_background.dart'; | ||||
| import 'package:surface/widgets/navigation/app_scaffold.dart'; | ||||
|  | ||||
| Widget _fadeThroughTransition( | ||||
| @@ -48,18 +49,12 @@ final _appRoutes = [ | ||||
|   GoRoute( | ||||
|     path: '/', | ||||
|     name: 'home', | ||||
|     pageBuilder: (context, state) => CustomTransitionPage( | ||||
|       transitionsBuilder: _fadeThroughTransition, | ||||
|       child: const HomeScreen(), | ||||
|     ), | ||||
|     builder: (context, state) => const HomeScreen(), | ||||
|   ), | ||||
|   GoRoute( | ||||
|     path: '/posts', | ||||
|     name: 'explore', | ||||
|     pageBuilder: (context, state) => CustomTransitionPage( | ||||
|       transitionsBuilder: _fadeThroughTransition, | ||||
|       child: const ExploreScreen(), | ||||
|     ), | ||||
|     builder: (context, state) => const ExploreScreen(), | ||||
|     routes: [ | ||||
|       GoRoute( | ||||
|         path: '/write/:mode', | ||||
| @@ -104,64 +99,42 @@ final _appRoutes = [ | ||||
|   GoRoute( | ||||
|     path: '/account', | ||||
|     name: 'account', | ||||
|     pageBuilder: (context, state) => CustomTransitionPage( | ||||
|       transitionsBuilder: _fadeThroughTransition, | ||||
|       child: const AccountScreen(), | ||||
|     ), | ||||
|     builder: (context, state) => const AccountScreen(), | ||||
|   ), | ||||
|   GoRoute( | ||||
|     path: '/chat', | ||||
|     name: 'chat', | ||||
|     pageBuilder: (context, state) => CustomTransitionPage( | ||||
|       transitionsBuilder: _fadeThroughTransition, | ||||
|       child: const ChatScreen(), | ||||
|     ), | ||||
|     builder: (context, state) => const ChatScreen(), | ||||
|     routes: [ | ||||
|       GoRoute( | ||||
|         path: '/:scope/:alias', | ||||
|         name: 'chatRoom', | ||||
|         builder: (context, state) => AppBackground( | ||||
|           child: ChatRoomScreen( | ||||
|             scope: state.pathParameters['scope']!, | ||||
|             alias: state.pathParameters['alias']!, | ||||
|           ), | ||||
|         builder: (context, state) => ChatRoomScreen( | ||||
|           scope: state.pathParameters['scope']!, | ||||
|           alias: state.pathParameters['alias']!, | ||||
|         ), | ||||
|       ), | ||||
|       GoRoute( | ||||
|         path: '/:scope/:alias/call', | ||||
|         name: 'chatCallRoom', | ||||
|         builder: (context, state) => AppBackground( | ||||
|           child: CallRoomScreen( | ||||
|             scope: state.pathParameters['scope']!, | ||||
|             alias: state.pathParameters['alias']!, | ||||
|           ), | ||||
|         builder: (context, state) => CallRoomScreen( | ||||
|           scope: state.pathParameters['scope']!, | ||||
|           alias: state.pathParameters['alias']!, | ||||
|         ), | ||||
|       ), | ||||
|       GoRoute( | ||||
|         path: '/:scope/:alias/detail', | ||||
|         name: 'channelDetail', | ||||
|         builder: (context, state) => AppBackground( | ||||
|           child: ChannelDetailScreen( | ||||
|             scope: state.pathParameters['scope']!, | ||||
|             alias: state.pathParameters['alias']!, | ||||
|           ), | ||||
|         builder: (context, state) => ChannelDetailScreen( | ||||
|           scope: state.pathParameters['scope']!, | ||||
|           alias: state.pathParameters['alias']!, | ||||
|         ), | ||||
|       ), | ||||
|       GoRoute( | ||||
|         path: '/manage', | ||||
|         name: 'chatManage', | ||||
|         pageBuilder: (context, state) => CustomTransitionPage( | ||||
|           child: ChatManageScreen( | ||||
|             editingChannelAlias: state.uri.queryParameters['editing'], | ||||
|           ), | ||||
|           transitionsBuilder: (context, animation, secondaryAnimation, child) { | ||||
|             return FadeThroughTransition( | ||||
|               animation: animation, | ||||
|               secondaryAnimation: secondaryAnimation, | ||||
|               fillColor: Colors.transparent, | ||||
|               child: child, | ||||
|             ); | ||||
|           }, | ||||
|         builder: (context, state) => ChatManageScreen( | ||||
|           editingChannelAlias: state.uri.queryParameters['editing'], | ||||
|         ), | ||||
|       ), | ||||
|     ], | ||||
| @@ -182,36 +155,40 @@ final _appRoutes = [ | ||||
|       GoRoute( | ||||
|         path: '/manage', | ||||
|         name: 'realmManage', | ||||
|         pageBuilder: (context, state) => CustomTransitionPage( | ||||
|           transitionsBuilder: _fadeThroughTransition, | ||||
|           child: RealmManageScreen( | ||||
|             editingRealmAlias: state.uri.queryParameters['editing'], | ||||
|           ), | ||||
|         builder: (context, state) => RealmManageScreen( | ||||
|           editingRealmAlias: state.uri.queryParameters['editing'], | ||||
|         ), | ||||
|       ), | ||||
|     ], | ||||
|   ), | ||||
|   GoRoute( | ||||
|     path: '/news', | ||||
|     name: 'news', | ||||
|     builder: (context, state) => const NewsScreen(), | ||||
|     routes: [ | ||||
|       GoRoute( | ||||
|         path: '/:hash', | ||||
|         name: 'newsDetail', | ||||
|         builder: (context, state) => NewsDetailScreen( | ||||
|           hash: state.pathParameters['hash']!, | ||||
|         ), | ||||
|       ), | ||||
|     ] | ||||
|   ), | ||||
|   GoRoute( | ||||
|     path: '/album', | ||||
|     name: 'album', | ||||
|     pageBuilder: (context, state) => CustomTransitionPage( | ||||
|       transitionsBuilder: _fadeThroughTransition, | ||||
|       child: const AlbumScreen(), | ||||
|     ), | ||||
|     builder: (context, state) => const AlbumScreen(), | ||||
|   ), | ||||
|   GoRoute( | ||||
|     path: '/friend', | ||||
|     name: 'friend', | ||||
|     pageBuilder: (context, state) => NoTransitionPage( | ||||
|       child: const FriendScreen(), | ||||
|     ), | ||||
|     builder: (context, state) => const FriendScreen(), | ||||
|   ), | ||||
|   GoRoute( | ||||
|     path: '/notification', | ||||
|     name: 'notification', | ||||
|     pageBuilder: (context, state) => NoTransitionPage( | ||||
|       child: const NotificationScreen(), | ||||
|     ), | ||||
|     builder: (context, state) => const NotificationScreen(), | ||||
|   ), | ||||
|   GoRoute( | ||||
|     path: '/auth/login', | ||||
|   | ||||
							
								
								
									
										230
									
								
								lib/screens/news/news_detail.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										230
									
								
								lib/screens/news/news_detail.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,230 @@ | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:flutter/gestures.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:gap/gap.dart'; | ||||
| import 'package:html/dom.dart' as dom; | ||||
| import 'package:html/parser.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
| import 'package:relative_time/relative_time.dart'; | ||||
| import 'package:styled_widget/styled_widget.dart'; | ||||
| import 'package:surface/providers/sn_network.dart'; | ||||
| import 'package:surface/types/news.dart'; | ||||
| import 'package:surface/widgets/dialog.dart'; | ||||
| import 'package:surface/widgets/navigation/app_scaffold.dart'; | ||||
| import 'package:flutter_inappwebview/flutter_inappwebview.dart'; | ||||
| import 'package:surface/widgets/universal_image.dart'; | ||||
| import 'package:url_launcher/url_launcher_string.dart'; | ||||
|  | ||||
| class NewsDetailScreen extends StatefulWidget { | ||||
|   final String hash; | ||||
|  | ||||
|   const NewsDetailScreen({super.key, required this.hash}); | ||||
|  | ||||
|   @override | ||||
|   State<NewsDetailScreen> createState() => _NewsDetailScreenState(); | ||||
| } | ||||
|  | ||||
| class _NewsDetailScreenState extends State<NewsDetailScreen> { | ||||
|   SnNewsArticle? _article; | ||||
|   dom.Document? _articleFragment; | ||||
|  | ||||
|   Future<void> _fetchArticle() async { | ||||
|     try { | ||||
|       final sn = context.read<SnNetworkProvider>(); | ||||
|       final resp = await sn.client.get('/cgi/re/news/${widget.hash}'); | ||||
|       _article = SnNewsArticle.fromJson(resp.data); | ||||
|       _articleFragment = parse(_article!.content); | ||||
|     } catch (err) { | ||||
|       if (!mounted) return; | ||||
|       context.showErrorDialog(err).then((_) { | ||||
|         if (!mounted) return; | ||||
|         Navigator.pop(context); | ||||
|       }); | ||||
|     } finally { | ||||
|       setState(() {}); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   List<Widget> _parseHtmlToWidgets(Iterable<dom.Element>? elements) { | ||||
|     if (elements == null) return []; | ||||
|  | ||||
|     final List<Widget> widgets = []; | ||||
|  | ||||
|     for (final node in elements) { | ||||
|       switch (node.localName) { | ||||
|         case 'h1': | ||||
|         case 'h2': | ||||
|         case 'h3': | ||||
|         case 'h4': | ||||
|         case 'h5': | ||||
|         case 'h6': | ||||
|           widgets.add(Text(node.text.trim(), style: Theme.of(context).textTheme.titleMedium)); | ||||
|           break; | ||||
|         case 'p': | ||||
|           if (node.text.trim().isEmpty) continue; | ||||
|           widgets.add( | ||||
|             Text.rich( | ||||
|               TextSpan( | ||||
|                 text: node.text.trim(), | ||||
|                 children: [ | ||||
|                   for (final child in node.children) | ||||
|                     switch (child.localName) { | ||||
|                       'a' => TextSpan( | ||||
|                           text: child.text.trim(), | ||||
|                           style: const TextStyle(decoration: TextDecoration.underline), | ||||
|                           recognizer: TapGestureRecognizer() | ||||
|                             ..onTap = () { | ||||
|                               launchUrlString(child.attributes['href']!); | ||||
|                             }, | ||||
|                         ), | ||||
|                       _ => TextSpan(text: child.text.trim()), | ||||
|                     }, | ||||
|                 ], | ||||
|               ), | ||||
|               style: Theme.of(context).textTheme.bodyLarge, | ||||
|             ), | ||||
|           ); | ||||
|           break; | ||||
|         case 'a': | ||||
|           // drop single link | ||||
|           break; | ||||
|         case 'div': | ||||
|           // ignore div text, normally it is not meaningful | ||||
|           widgets.addAll(_parseHtmlToWidgets(node.children)); | ||||
|           break; | ||||
|         case 'hr': | ||||
|           widgets.add(const Divider()); | ||||
|           break; | ||||
|         case 'img': | ||||
|           var src = node.attributes['src']; | ||||
|           if (src == null) break; | ||||
|           final width = double.tryParse(node.attributes['width'] ?? 'null'); | ||||
|           final height = double.tryParse(node.attributes['height'] ?? 'null'); | ||||
|           final ratio = width != null && height != null ? width / height : 1.0; | ||||
|           if (!src.startsWith('http')) { | ||||
|             final baseUri = Uri.parse(_article!.url); | ||||
|             final baseUrl = '${baseUri.scheme}://${baseUri.host}'; | ||||
|             src = '$baseUrl/$src'; | ||||
|           } | ||||
|           widgets.add( | ||||
|             AspectRatio( | ||||
|               aspectRatio: ratio, | ||||
|               child: Container( | ||||
|                 decoration: BoxDecoration( | ||||
|                   borderRadius: BorderRadius.all(Radius.circular(8)), | ||||
|                   border: Border.all( | ||||
|                     color: Theme.of(context).dividerColor, | ||||
|                     width: 1, | ||||
|                   ), | ||||
|                 ), | ||||
|                 height: height ?? double.infinity, | ||||
|                 child: ClipRRect( | ||||
|                   borderRadius: BorderRadius.all(Radius.circular(8)), | ||||
|                   child: AutoResizeUniversalImage(src, fit: BoxFit.cover), | ||||
|                 ), | ||||
|               ), | ||||
|             ), | ||||
|           ); | ||||
|           break; | ||||
|         default: | ||||
|           widgets.addAll(_parseHtmlToWidgets(node.children)); | ||||
|           break; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return widgets; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   void initState() { | ||||
|     super.initState(); | ||||
|     _fetchArticle(); | ||||
|   } | ||||
|  | ||||
|   bool _isReadingFromReader = true; | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return AppScaffold( | ||||
|       appBar: AppBar( | ||||
|         leading: const PageBackButton(), | ||||
|         title: Text(_article?.title ?? 'loading'.tr()), | ||||
|       ), | ||||
|       body: Column( | ||||
|         children: [ | ||||
|           MaterialBanner( | ||||
|             dividerColor: Colors.transparent, | ||||
|             leading: const Icon(Icons.info), | ||||
|             content: Text(_isReadingFromReader ? 'newsReadingFromReader'.tr() : 'newsReadingFromOriginal'.tr()), | ||||
|             actions: [ | ||||
|               TextButton( | ||||
|                 child: Text('newsReadingProviderSwap').tr(), | ||||
|                 onPressed: () { | ||||
|                   setState(() => _isReadingFromReader = !_isReadingFromReader); | ||||
|                 }, | ||||
|               ), | ||||
|             ], | ||||
|           ), | ||||
|           if (_articleFragment != null && _isReadingFromReader) | ||||
|             Expanded( | ||||
|               child: SingleChildScrollView( | ||||
|                 child: Column( | ||||
|                   crossAxisAlignment: CrossAxisAlignment.start, | ||||
|                   spacing: 8, | ||||
|                   children: [ | ||||
|                     Text(_article!.title, style: Theme.of(context).textTheme.titleLarge), | ||||
|                     Builder(builder: (context) { | ||||
|                       final htmlDescription = parse(_article!.description); | ||||
|                       return Text( | ||||
|                         htmlDescription.children.map((ele) => ele.text.trim()).join(), | ||||
|                         style: Theme.of(context).textTheme.bodyMedium, | ||||
|                       ); | ||||
|                     }), | ||||
|                     Builder(builder: (context) { | ||||
|                       final date = _article!.publishedAt ?? _article!.createdAt; | ||||
|                       return Row( | ||||
|                         spacing: 2, | ||||
|                         children: [ | ||||
|                           Text(DateFormat().format(date)).textStyle(Theme.of(context).textTheme.bodySmall!), | ||||
|                           Text(' · ').textStyle(Theme.of(context).textTheme.bodySmall!).bold(), | ||||
|                           Text(RelativeTime(context).format(date)).textStyle(Theme.of(context).textTheme.bodySmall!), | ||||
|                         ], | ||||
|                       ).opacity(0.75); | ||||
|                     }), | ||||
|                     Text('newsDisclaimer').tr().textStyle(Theme.of(context).textTheme.bodySmall!).opacity(0.75), | ||||
|                     const Divider(), | ||||
|                     ..._parseHtmlToWidgets(_articleFragment!.children), | ||||
|                     const Divider(), | ||||
|                     InkWell( | ||||
|                       child: Row( | ||||
|                         mainAxisSize: MainAxisSize.min, | ||||
|                         children: [ | ||||
|                           Text( | ||||
|                             'Reference from original website', | ||||
|                             style: TextStyle(decoration: TextDecoration.underline), | ||||
|                           ), | ||||
|                           const Gap(4), | ||||
|                           Icon(Icons.launch, size: 16), | ||||
|                         ], | ||||
|                       ).opacity(0.85), | ||||
|                       onTap: () { | ||||
|                         launchUrlString(_article!.url); | ||||
|                       }, | ||||
|                     ), | ||||
|                     Gap(MediaQuery.of(context).padding.bottom), | ||||
|                   ], | ||||
|                 ).padding(horizontal: 12, vertical: 16), | ||||
|               ), | ||||
|             ) | ||||
|           else if (_article != null) | ||||
|             Expanded( | ||||
|               child: InAppWebView( | ||||
|                 key: GlobalKey(), | ||||
|                 initialUrlRequest: URLRequest(url: WebUri(_article!.url)), | ||||
|               ), | ||||
|             ), | ||||
|         ], | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										221
									
								
								lib/screens/news/news_list.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										221
									
								
								lib/screens/news/news_list.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,221 @@ | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:gap/gap.dart'; | ||||
| import 'package:go_router/go_router.dart'; | ||||
| import 'package:html/parser.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
| import 'package:relative_time/relative_time.dart'; | ||||
| import 'package:styled_widget/styled_widget.dart'; | ||||
| import 'package:surface/providers/sn_network.dart'; | ||||
| import 'package:surface/types/news.dart'; | ||||
| import 'package:surface/widgets/app_bar_leading.dart'; | ||||
| import 'package:surface/widgets/dialog.dart'; | ||||
| import 'package:surface/widgets/navigation/app_scaffold.dart'; | ||||
| import 'package:surface/widgets/universal_image.dart'; | ||||
| import 'package:very_good_infinite_list/very_good_infinite_list.dart'; | ||||
|  | ||||
| class NewsScreen extends StatefulWidget { | ||||
|   const NewsScreen({super.key}); | ||||
|  | ||||
|   @override | ||||
|   State<NewsScreen> createState() => _NewsScreenState(); | ||||
| } | ||||
|  | ||||
| class _NewsScreenState extends State<NewsScreen> { | ||||
|   List<SnNewsSource>? _sources; | ||||
|  | ||||
|   @override | ||||
|   initState() { | ||||
|     super.initState(); | ||||
|     _fetchSources(); | ||||
|   } | ||||
|  | ||||
|   Future<void> _fetchSources() async { | ||||
|     try { | ||||
|       final sn = context.read<SnNetworkProvider>(); | ||||
|       final resp = await sn.client.get('/cgi/re/well-known/sources'); | ||||
|       _sources = List<SnNewsSource>.from( | ||||
|         resp.data?.map((e) => SnNewsSource.fromJson(e)) ?? [], | ||||
|       ); | ||||
|     } catch (err) { | ||||
|       if (!mounted) return; | ||||
|       context.showErrorDialog(err); | ||||
|     } finally { | ||||
|       setState(() {}); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     if (_sources == null) { | ||||
|       return AppScaffold( | ||||
|         appBar: AppBar( | ||||
|           leading: AutoAppBarLeading(), | ||||
|           title: Text('screenNews').tr(), | ||||
|         ), | ||||
|         body: Center( | ||||
|           child: CircularProgressIndicator(), | ||||
|         ), | ||||
|       ); | ||||
|     } | ||||
|  | ||||
|     return DefaultTabController( | ||||
|       length: _sources!.length + 1, | ||||
|       child: AppScaffold( | ||||
|         body: NestedScrollView( | ||||
|           headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { | ||||
|             return <Widget>[ | ||||
|               SliverOverlapAbsorber( | ||||
|                 handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), | ||||
|                 sliver: SliverAppBar( | ||||
|                   leading: AutoAppBarLeading(), | ||||
|                   title: Text('screenNews').tr(), | ||||
|                   bottom: TabBar( | ||||
|                     isScrollable: true, | ||||
|                     tabs: [ | ||||
|                       Tab(child: Text('newsAllSources'.tr())), | ||||
|                       for (final source in _sources!) Tab(child: Text(source.label)), | ||||
|                     ], | ||||
|                   ), | ||||
|                 ), | ||||
|               ), | ||||
|             ]; | ||||
|           }, | ||||
|           body: TabBarView( | ||||
|             children: [ | ||||
|               _NewsArticleListWidget(allSources: _sources!), | ||||
|               for (final source in _sources!) | ||||
|                 _NewsArticleListWidget( | ||||
|                   source: source.id, | ||||
|                   allSources: _sources!, | ||||
|                 ), | ||||
|             ], | ||||
|           ), | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class _NewsArticleListWidget extends StatefulWidget { | ||||
|   final String? source; | ||||
|   final List<SnNewsSource> allSources; | ||||
|  | ||||
|   const _NewsArticleListWidget({this.source, required this.allSources}); | ||||
|  | ||||
|   @override | ||||
|   State<_NewsArticleListWidget> createState() => _NewsArticleListWidgetState(); | ||||
| } | ||||
|  | ||||
| class _NewsArticleListWidgetState extends State<_NewsArticleListWidget> { | ||||
|   bool _isBusy = false; | ||||
|  | ||||
|   int? _totalCount; | ||||
|   final List<SnNewsArticle> _articles = List.empty(growable: true); | ||||
|  | ||||
|   Future<void> _fetchArticles() async { | ||||
|     setState(() => _isBusy = true); | ||||
|  | ||||
|     try { | ||||
|       final sn = context.read<SnNetworkProvider>(); | ||||
|       final resp = await sn.client.get('/cgi/re/news', queryParameters: { | ||||
|         'take': 10, | ||||
|         'offset': _articles.length, | ||||
|         if (widget.source != null) 'source': widget.source, | ||||
|       }); | ||||
|       _totalCount = resp.data['count']; | ||||
|       _articles.addAll(List<SnNewsArticle>.from( | ||||
|         resp.data['data']?.map((e) => SnNewsArticle.fromJson(e)) ?? [], | ||||
|       )); | ||||
|     } catch (err) { | ||||
|       if (!mounted) return; | ||||
|       context.showErrorDialog(err); | ||||
|     } finally { | ||||
|       setState(() => _isBusy = false); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   void initState() { | ||||
|     super.initState(); | ||||
|     _fetchArticles(); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return MediaQuery.removePadding( | ||||
|       context: context, | ||||
|       removeTop: true, | ||||
|       child: RefreshIndicator( | ||||
|         onRefresh: _fetchArticles, | ||||
|         child: InfiniteList( | ||||
|           isLoading: _isBusy, | ||||
|           itemCount: _articles.length, | ||||
|           hasReachedMax: _totalCount != null && _articles.length >= _totalCount!, | ||||
|           onFetchData: () { | ||||
|             _fetchArticles(); | ||||
|           }, | ||||
|           itemBuilder: (context, index) { | ||||
|             final article = _articles[index]; | ||||
|  | ||||
|             final baseUri = Uri.parse(article.url); | ||||
|             final baseUrl = '${baseUri.scheme}://${baseUri.host}'; | ||||
|  | ||||
|             final htmlDescription = parse(article.description); | ||||
|             final date = article.publishedAt ?? article.createdAt; | ||||
|  | ||||
|             return Card( | ||||
|               child: InkWell( | ||||
|                 radius: 8, | ||||
|                 onTap: () { | ||||
|                   GoRouter.of(context).pushNamed( | ||||
|                     'newsDetail', | ||||
|                     pathParameters: {'hash': article.hash}, | ||||
|                   ); | ||||
|                 }, | ||||
|                 child: Column( | ||||
|                   crossAxisAlignment: CrossAxisAlignment.start, | ||||
|                   children: [ | ||||
|                     if (article.thumbnail.isNotEmpty && !article.thumbnail.endsWith('.svg')) | ||||
|                       ClipRRect( | ||||
|                         borderRadius: BorderRadius.all(Radius.circular(8)), | ||||
|                         child: AspectRatio( | ||||
|                           aspectRatio: 16 / 9, | ||||
|                           child: AutoResizeUniversalImage( | ||||
|                             article.thumbnail.startsWith('http') ? article.thumbnail : '$baseUrl/${article.thumbnail}', | ||||
|                           ), | ||||
|                         ), | ||||
|                       ), | ||||
|                     const Gap(16), | ||||
|                     Text(article.title).textStyle(Theme.of(context).textTheme.titleLarge!).padding(horizontal: 16), | ||||
|                     const Gap(8), | ||||
|                     Text(htmlDescription.children.map((ele) => ele.text.trim()).join()) | ||||
|                         .textStyle(Theme.of(context).textTheme.bodyMedium!) | ||||
|                         .padding(horizontal: 16), | ||||
|                     const Gap(8), | ||||
|                     Row( | ||||
|                       spacing: 2, | ||||
|                       children: [ | ||||
|                         Text(widget.allSources.where((x) => x.id == article.source).first.label) | ||||
|                             .textStyle(Theme.of(context).textTheme.bodySmall!), | ||||
|                       ], | ||||
|                     ).opacity(0.75).padding(horizontal: 16), | ||||
|                     Row( | ||||
|                       spacing: 2, | ||||
|                       children: [ | ||||
|                         Text(DateFormat().format(date)).textStyle(Theme.of(context).textTheme.bodySmall!), | ||||
|                         Text(' · ').textStyle(Theme.of(context).textTheme.bodySmall!).bold(), | ||||
|                         Text(RelativeTime(context).format(date)).textStyle(Theme.of(context).textTheme.bodySmall!), | ||||
|                       ], | ||||
|                     ).opacity(0.75).padding(horizontal: 16), | ||||
|                     const Gap(16), | ||||
|                   ], | ||||
|                 ), | ||||
|               ), | ||||
|             ); | ||||
|           }, | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										38
									
								
								lib/types/news.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								lib/types/news.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| import 'package:freezed_annotation/freezed_annotation.dart'; | ||||
|  | ||||
| part 'news.freezed.dart'; | ||||
| part 'news.g.dart'; | ||||
|  | ||||
| @freezed | ||||
| class SnNewsSource with _$SnNewsSource { | ||||
|   const factory SnNewsSource({ | ||||
|     required String id, | ||||
|     required String label, | ||||
|     required String type, | ||||
|     required String source, | ||||
|     required int depth, | ||||
|     required bool enabled, | ||||
|   }) = _SnNewsSource; | ||||
|  | ||||
|   factory SnNewsSource.fromJson(Map<String, dynamic> json) => _$SnNewsSourceFromJson(json); | ||||
| } | ||||
|  | ||||
| @freezed | ||||
| class SnNewsArticle with _$SnNewsArticle { | ||||
|   const factory SnNewsArticle({ | ||||
|     required int id, | ||||
|     required DateTime createdAt, | ||||
|     required DateTime updatedAt, | ||||
|     required dynamic deletedAt, | ||||
|     required String thumbnail, | ||||
|     required String title, | ||||
|     required String description, | ||||
|     required String content, | ||||
|     required String url, | ||||
|     required String hash, | ||||
|     required String source, | ||||
|     required DateTime? publishedAt, | ||||
|   }) = _SnNewsArticle; | ||||
|  | ||||
|   factory SnNewsArticle.fromJson(Map<String, dynamic> json) => _$SnNewsArticleFromJson(json); | ||||
| } | ||||
							
								
								
									
										660
									
								
								lib/types/news.freezed.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										660
									
								
								lib/types/news.freezed.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,660 @@ | ||||
| // coverage:ignore-file | ||||
| // GENERATED CODE - DO NOT MODIFY BY HAND | ||||
| // ignore_for_file: type=lint | ||||
| // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark | ||||
|  | ||||
| part of 'news.dart'; | ||||
|  | ||||
| // ************************************************************************** | ||||
| // FreezedGenerator | ||||
| // ************************************************************************** | ||||
|  | ||||
| T _$identity<T>(T value) => value; | ||||
|  | ||||
| final _privateConstructorUsedError = UnsupportedError( | ||||
|     'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); | ||||
|  | ||||
| SnNewsSource _$SnNewsSourceFromJson(Map<String, dynamic> json) { | ||||
|   return _SnNewsSource.fromJson(json); | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| mixin _$SnNewsSource { | ||||
|   String get id => throw _privateConstructorUsedError; | ||||
|   String get label => throw _privateConstructorUsedError; | ||||
|   String get type => throw _privateConstructorUsedError; | ||||
|   String get source => throw _privateConstructorUsedError; | ||||
|   int get depth => throw _privateConstructorUsedError; | ||||
|   bool get enabled => throw _privateConstructorUsedError; | ||||
|  | ||||
|   /// Serializes this SnNewsSource to a JSON map. | ||||
|   Map<String, dynamic> toJson() => throw _privateConstructorUsedError; | ||||
|  | ||||
|   /// Create a copy of SnNewsSource | ||||
|   /// with the given fields replaced by the non-null parameter values. | ||||
|   @JsonKey(includeFromJson: false, includeToJson: false) | ||||
|   $SnNewsSourceCopyWith<SnNewsSource> get copyWith => | ||||
|       throw _privateConstructorUsedError; | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| abstract class $SnNewsSourceCopyWith<$Res> { | ||||
|   factory $SnNewsSourceCopyWith( | ||||
|           SnNewsSource value, $Res Function(SnNewsSource) then) = | ||||
|       _$SnNewsSourceCopyWithImpl<$Res, SnNewsSource>; | ||||
|   @useResult | ||||
|   $Res call( | ||||
|       {String id, | ||||
|       String label, | ||||
|       String type, | ||||
|       String source, | ||||
|       int depth, | ||||
|       bool enabled}); | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| class _$SnNewsSourceCopyWithImpl<$Res, $Val extends SnNewsSource> | ||||
|     implements $SnNewsSourceCopyWith<$Res> { | ||||
|   _$SnNewsSourceCopyWithImpl(this._value, this._then); | ||||
|  | ||||
|   // ignore: unused_field | ||||
|   final $Val _value; | ||||
|   // ignore: unused_field | ||||
|   final $Res Function($Val) _then; | ||||
|  | ||||
|   /// Create a copy of SnNewsSource | ||||
|   /// with the given fields replaced by the non-null parameter values. | ||||
|   @pragma('vm:prefer-inline') | ||||
|   @override | ||||
|   $Res call({ | ||||
|     Object? id = null, | ||||
|     Object? label = null, | ||||
|     Object? type = null, | ||||
|     Object? source = null, | ||||
|     Object? depth = null, | ||||
|     Object? enabled = null, | ||||
|   }) { | ||||
|     return _then(_value.copyWith( | ||||
|       id: null == id | ||||
|           ? _value.id | ||||
|           : id // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       label: null == label | ||||
|           ? _value.label | ||||
|           : label // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       type: null == type | ||||
|           ? _value.type | ||||
|           : type // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       source: null == source | ||||
|           ? _value.source | ||||
|           : source // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       depth: null == depth | ||||
|           ? _value.depth | ||||
|           : depth // ignore: cast_nullable_to_non_nullable | ||||
|               as int, | ||||
|       enabled: null == enabled | ||||
|           ? _value.enabled | ||||
|           : enabled // ignore: cast_nullable_to_non_nullable | ||||
|               as bool, | ||||
|     ) as $Val); | ||||
|   } | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| abstract class _$$SnNewsSourceImplCopyWith<$Res> | ||||
|     implements $SnNewsSourceCopyWith<$Res> { | ||||
|   factory _$$SnNewsSourceImplCopyWith( | ||||
|           _$SnNewsSourceImpl value, $Res Function(_$SnNewsSourceImpl) then) = | ||||
|       __$$SnNewsSourceImplCopyWithImpl<$Res>; | ||||
|   @override | ||||
|   @useResult | ||||
|   $Res call( | ||||
|       {String id, | ||||
|       String label, | ||||
|       String type, | ||||
|       String source, | ||||
|       int depth, | ||||
|       bool enabled}); | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| class __$$SnNewsSourceImplCopyWithImpl<$Res> | ||||
|     extends _$SnNewsSourceCopyWithImpl<$Res, _$SnNewsSourceImpl> | ||||
|     implements _$$SnNewsSourceImplCopyWith<$Res> { | ||||
|   __$$SnNewsSourceImplCopyWithImpl( | ||||
|       _$SnNewsSourceImpl _value, $Res Function(_$SnNewsSourceImpl) _then) | ||||
|       : super(_value, _then); | ||||
|  | ||||
|   /// Create a copy of SnNewsSource | ||||
|   /// with the given fields replaced by the non-null parameter values. | ||||
|   @pragma('vm:prefer-inline') | ||||
|   @override | ||||
|   $Res call({ | ||||
|     Object? id = null, | ||||
|     Object? label = null, | ||||
|     Object? type = null, | ||||
|     Object? source = null, | ||||
|     Object? depth = null, | ||||
|     Object? enabled = null, | ||||
|   }) { | ||||
|     return _then(_$SnNewsSourceImpl( | ||||
|       id: null == id | ||||
|           ? _value.id | ||||
|           : id // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       label: null == label | ||||
|           ? _value.label | ||||
|           : label // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       type: null == type | ||||
|           ? _value.type | ||||
|           : type // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       source: null == source | ||||
|           ? _value.source | ||||
|           : source // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       depth: null == depth | ||||
|           ? _value.depth | ||||
|           : depth // ignore: cast_nullable_to_non_nullable | ||||
|               as int, | ||||
|       enabled: null == enabled | ||||
|           ? _value.enabled | ||||
|           : enabled // ignore: cast_nullable_to_non_nullable | ||||
|               as bool, | ||||
|     )); | ||||
|   } | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| @JsonSerializable() | ||||
| class _$SnNewsSourceImpl implements _SnNewsSource { | ||||
|   const _$SnNewsSourceImpl( | ||||
|       {required this.id, | ||||
|       required this.label, | ||||
|       required this.type, | ||||
|       required this.source, | ||||
|       required this.depth, | ||||
|       required this.enabled}); | ||||
|  | ||||
|   factory _$SnNewsSourceImpl.fromJson(Map<String, dynamic> json) => | ||||
|       _$$SnNewsSourceImplFromJson(json); | ||||
|  | ||||
|   @override | ||||
|   final String id; | ||||
|   @override | ||||
|   final String label; | ||||
|   @override | ||||
|   final String type; | ||||
|   @override | ||||
|   final String source; | ||||
|   @override | ||||
|   final int depth; | ||||
|   @override | ||||
|   final bool enabled; | ||||
|  | ||||
|   @override | ||||
|   String toString() { | ||||
|     return 'SnNewsSource(id: $id, label: $label, type: $type, source: $source, depth: $depth, enabled: $enabled)'; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   bool operator ==(Object other) { | ||||
|     return identical(this, other) || | ||||
|         (other.runtimeType == runtimeType && | ||||
|             other is _$SnNewsSourceImpl && | ||||
|             (identical(other.id, id) || other.id == id) && | ||||
|             (identical(other.label, label) || other.label == label) && | ||||
|             (identical(other.type, type) || other.type == type) && | ||||
|             (identical(other.source, source) || other.source == source) && | ||||
|             (identical(other.depth, depth) || other.depth == depth) && | ||||
|             (identical(other.enabled, enabled) || other.enabled == enabled)); | ||||
|   } | ||||
|  | ||||
|   @JsonKey(includeFromJson: false, includeToJson: false) | ||||
|   @override | ||||
|   int get hashCode => | ||||
|       Object.hash(runtimeType, id, label, type, source, depth, enabled); | ||||
|  | ||||
|   /// Create a copy of SnNewsSource | ||||
|   /// with the given fields replaced by the non-null parameter values. | ||||
|   @JsonKey(includeFromJson: false, includeToJson: false) | ||||
|   @override | ||||
|   @pragma('vm:prefer-inline') | ||||
|   _$$SnNewsSourceImplCopyWith<_$SnNewsSourceImpl> get copyWith => | ||||
|       __$$SnNewsSourceImplCopyWithImpl<_$SnNewsSourceImpl>(this, _$identity); | ||||
|  | ||||
|   @override | ||||
|   Map<String, dynamic> toJson() { | ||||
|     return _$$SnNewsSourceImplToJson( | ||||
|       this, | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| abstract class _SnNewsSource implements SnNewsSource { | ||||
|   const factory _SnNewsSource( | ||||
|       {required final String id, | ||||
|       required final String label, | ||||
|       required final String type, | ||||
|       required final String source, | ||||
|       required final int depth, | ||||
|       required final bool enabled}) = _$SnNewsSourceImpl; | ||||
|  | ||||
|   factory _SnNewsSource.fromJson(Map<String, dynamic> json) = | ||||
|       _$SnNewsSourceImpl.fromJson; | ||||
|  | ||||
|   @override | ||||
|   String get id; | ||||
|   @override | ||||
|   String get label; | ||||
|   @override | ||||
|   String get type; | ||||
|   @override | ||||
|   String get source; | ||||
|   @override | ||||
|   int get depth; | ||||
|   @override | ||||
|   bool get enabled; | ||||
|  | ||||
|   /// Create a copy of SnNewsSource | ||||
|   /// with the given fields replaced by the non-null parameter values. | ||||
|   @override | ||||
|   @JsonKey(includeFromJson: false, includeToJson: false) | ||||
|   _$$SnNewsSourceImplCopyWith<_$SnNewsSourceImpl> get copyWith => | ||||
|       throw _privateConstructorUsedError; | ||||
| } | ||||
|  | ||||
| SnNewsArticle _$SnNewsArticleFromJson(Map<String, dynamic> json) { | ||||
|   return _SnNewsArticle.fromJson(json); | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| mixin _$SnNewsArticle { | ||||
|   int get id => throw _privateConstructorUsedError; | ||||
|   DateTime get createdAt => throw _privateConstructorUsedError; | ||||
|   DateTime get updatedAt => throw _privateConstructorUsedError; | ||||
|   dynamic get deletedAt => throw _privateConstructorUsedError; | ||||
|   String get thumbnail => throw _privateConstructorUsedError; | ||||
|   String get title => throw _privateConstructorUsedError; | ||||
|   String get description => throw _privateConstructorUsedError; | ||||
|   String get content => throw _privateConstructorUsedError; | ||||
|   String get url => throw _privateConstructorUsedError; | ||||
|   String get hash => throw _privateConstructorUsedError; | ||||
|   String get source => throw _privateConstructorUsedError; | ||||
|   DateTime? get publishedAt => throw _privateConstructorUsedError; | ||||
|  | ||||
|   /// Serializes this SnNewsArticle to a JSON map. | ||||
|   Map<String, dynamic> toJson() => throw _privateConstructorUsedError; | ||||
|  | ||||
|   /// Create a copy of SnNewsArticle | ||||
|   /// with the given fields replaced by the non-null parameter values. | ||||
|   @JsonKey(includeFromJson: false, includeToJson: false) | ||||
|   $SnNewsArticleCopyWith<SnNewsArticle> get copyWith => | ||||
|       throw _privateConstructorUsedError; | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| abstract class $SnNewsArticleCopyWith<$Res> { | ||||
|   factory $SnNewsArticleCopyWith( | ||||
|           SnNewsArticle value, $Res Function(SnNewsArticle) then) = | ||||
|       _$SnNewsArticleCopyWithImpl<$Res, SnNewsArticle>; | ||||
|   @useResult | ||||
|   $Res call( | ||||
|       {int id, | ||||
|       DateTime createdAt, | ||||
|       DateTime updatedAt, | ||||
|       dynamic deletedAt, | ||||
|       String thumbnail, | ||||
|       String title, | ||||
|       String description, | ||||
|       String content, | ||||
|       String url, | ||||
|       String hash, | ||||
|       String source, | ||||
|       DateTime? publishedAt}); | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| class _$SnNewsArticleCopyWithImpl<$Res, $Val extends SnNewsArticle> | ||||
|     implements $SnNewsArticleCopyWith<$Res> { | ||||
|   _$SnNewsArticleCopyWithImpl(this._value, this._then); | ||||
|  | ||||
|   // ignore: unused_field | ||||
|   final $Val _value; | ||||
|   // ignore: unused_field | ||||
|   final $Res Function($Val) _then; | ||||
|  | ||||
|   /// Create a copy of SnNewsArticle | ||||
|   /// with the given fields replaced by the non-null parameter values. | ||||
|   @pragma('vm:prefer-inline') | ||||
|   @override | ||||
|   $Res call({ | ||||
|     Object? id = null, | ||||
|     Object? createdAt = null, | ||||
|     Object? updatedAt = null, | ||||
|     Object? deletedAt = freezed, | ||||
|     Object? thumbnail = null, | ||||
|     Object? title = null, | ||||
|     Object? description = null, | ||||
|     Object? content = null, | ||||
|     Object? url = null, | ||||
|     Object? hash = null, | ||||
|     Object? source = null, | ||||
|     Object? publishedAt = freezed, | ||||
|   }) { | ||||
|     return _then(_value.copyWith( | ||||
|       id: null == id | ||||
|           ? _value.id | ||||
|           : id // ignore: cast_nullable_to_non_nullable | ||||
|               as int, | ||||
|       createdAt: null == createdAt | ||||
|           ? _value.createdAt | ||||
|           : createdAt // ignore: cast_nullable_to_non_nullable | ||||
|               as DateTime, | ||||
|       updatedAt: null == updatedAt | ||||
|           ? _value.updatedAt | ||||
|           : updatedAt // ignore: cast_nullable_to_non_nullable | ||||
|               as DateTime, | ||||
|       deletedAt: freezed == deletedAt | ||||
|           ? _value.deletedAt | ||||
|           : deletedAt // ignore: cast_nullable_to_non_nullable | ||||
|               as dynamic, | ||||
|       thumbnail: null == thumbnail | ||||
|           ? _value.thumbnail | ||||
|           : thumbnail // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       title: null == title | ||||
|           ? _value.title | ||||
|           : title // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       description: null == description | ||||
|           ? _value.description | ||||
|           : description // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       content: null == content | ||||
|           ? _value.content | ||||
|           : content // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       url: null == url | ||||
|           ? _value.url | ||||
|           : url // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       hash: null == hash | ||||
|           ? _value.hash | ||||
|           : hash // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       source: null == source | ||||
|           ? _value.source | ||||
|           : source // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       publishedAt: freezed == publishedAt | ||||
|           ? _value.publishedAt | ||||
|           : publishedAt // ignore: cast_nullable_to_non_nullable | ||||
|               as DateTime?, | ||||
|     ) as $Val); | ||||
|   } | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| abstract class _$$SnNewsArticleImplCopyWith<$Res> | ||||
|     implements $SnNewsArticleCopyWith<$Res> { | ||||
|   factory _$$SnNewsArticleImplCopyWith( | ||||
|           _$SnNewsArticleImpl value, $Res Function(_$SnNewsArticleImpl) then) = | ||||
|       __$$SnNewsArticleImplCopyWithImpl<$Res>; | ||||
|   @override | ||||
|   @useResult | ||||
|   $Res call( | ||||
|       {int id, | ||||
|       DateTime createdAt, | ||||
|       DateTime updatedAt, | ||||
|       dynamic deletedAt, | ||||
|       String thumbnail, | ||||
|       String title, | ||||
|       String description, | ||||
|       String content, | ||||
|       String url, | ||||
|       String hash, | ||||
|       String source, | ||||
|       DateTime? publishedAt}); | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| class __$$SnNewsArticleImplCopyWithImpl<$Res> | ||||
|     extends _$SnNewsArticleCopyWithImpl<$Res, _$SnNewsArticleImpl> | ||||
|     implements _$$SnNewsArticleImplCopyWith<$Res> { | ||||
|   __$$SnNewsArticleImplCopyWithImpl( | ||||
|       _$SnNewsArticleImpl _value, $Res Function(_$SnNewsArticleImpl) _then) | ||||
|       : super(_value, _then); | ||||
|  | ||||
|   /// Create a copy of SnNewsArticle | ||||
|   /// with the given fields replaced by the non-null parameter values. | ||||
|   @pragma('vm:prefer-inline') | ||||
|   @override | ||||
|   $Res call({ | ||||
|     Object? id = null, | ||||
|     Object? createdAt = null, | ||||
|     Object? updatedAt = null, | ||||
|     Object? deletedAt = freezed, | ||||
|     Object? thumbnail = null, | ||||
|     Object? title = null, | ||||
|     Object? description = null, | ||||
|     Object? content = null, | ||||
|     Object? url = null, | ||||
|     Object? hash = null, | ||||
|     Object? source = null, | ||||
|     Object? publishedAt = freezed, | ||||
|   }) { | ||||
|     return _then(_$SnNewsArticleImpl( | ||||
|       id: null == id | ||||
|           ? _value.id | ||||
|           : id // ignore: cast_nullable_to_non_nullable | ||||
|               as int, | ||||
|       createdAt: null == createdAt | ||||
|           ? _value.createdAt | ||||
|           : createdAt // ignore: cast_nullable_to_non_nullable | ||||
|               as DateTime, | ||||
|       updatedAt: null == updatedAt | ||||
|           ? _value.updatedAt | ||||
|           : updatedAt // ignore: cast_nullable_to_non_nullable | ||||
|               as DateTime, | ||||
|       deletedAt: freezed == deletedAt | ||||
|           ? _value.deletedAt | ||||
|           : deletedAt // ignore: cast_nullable_to_non_nullable | ||||
|               as dynamic, | ||||
|       thumbnail: null == thumbnail | ||||
|           ? _value.thumbnail | ||||
|           : thumbnail // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       title: null == title | ||||
|           ? _value.title | ||||
|           : title // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       description: null == description | ||||
|           ? _value.description | ||||
|           : description // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       content: null == content | ||||
|           ? _value.content | ||||
|           : content // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       url: null == url | ||||
|           ? _value.url | ||||
|           : url // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       hash: null == hash | ||||
|           ? _value.hash | ||||
|           : hash // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       source: null == source | ||||
|           ? _value.source | ||||
|           : source // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       publishedAt: freezed == publishedAt | ||||
|           ? _value.publishedAt | ||||
|           : publishedAt // ignore: cast_nullable_to_non_nullable | ||||
|               as DateTime?, | ||||
|     )); | ||||
|   } | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| @JsonSerializable() | ||||
| class _$SnNewsArticleImpl implements _SnNewsArticle { | ||||
|   const _$SnNewsArticleImpl( | ||||
|       {required this.id, | ||||
|       required this.createdAt, | ||||
|       required this.updatedAt, | ||||
|       required this.deletedAt, | ||||
|       required this.thumbnail, | ||||
|       required this.title, | ||||
|       required this.description, | ||||
|       required this.content, | ||||
|       required this.url, | ||||
|       required this.hash, | ||||
|       required this.source, | ||||
|       required this.publishedAt}); | ||||
|  | ||||
|   factory _$SnNewsArticleImpl.fromJson(Map<String, dynamic> json) => | ||||
|       _$$SnNewsArticleImplFromJson(json); | ||||
|  | ||||
|   @override | ||||
|   final int id; | ||||
|   @override | ||||
|   final DateTime createdAt; | ||||
|   @override | ||||
|   final DateTime updatedAt; | ||||
|   @override | ||||
|   final dynamic deletedAt; | ||||
|   @override | ||||
|   final String thumbnail; | ||||
|   @override | ||||
|   final String title; | ||||
|   @override | ||||
|   final String description; | ||||
|   @override | ||||
|   final String content; | ||||
|   @override | ||||
|   final String url; | ||||
|   @override | ||||
|   final String hash; | ||||
|   @override | ||||
|   final String source; | ||||
|   @override | ||||
|   final DateTime? publishedAt; | ||||
|  | ||||
|   @override | ||||
|   String toString() { | ||||
|     return 'SnNewsArticle(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, thumbnail: $thumbnail, title: $title, description: $description, content: $content, url: $url, hash: $hash, source: $source, publishedAt: $publishedAt)'; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   bool operator ==(Object other) { | ||||
|     return identical(this, other) || | ||||
|         (other.runtimeType == runtimeType && | ||||
|             other is _$SnNewsArticleImpl && | ||||
|             (identical(other.id, id) || other.id == id) && | ||||
|             (identical(other.createdAt, createdAt) || | ||||
|                 other.createdAt == createdAt) && | ||||
|             (identical(other.updatedAt, updatedAt) || | ||||
|                 other.updatedAt == updatedAt) && | ||||
|             const DeepCollectionEquality().equals(other.deletedAt, deletedAt) && | ||||
|             (identical(other.thumbnail, thumbnail) || | ||||
|                 other.thumbnail == thumbnail) && | ||||
|             (identical(other.title, title) || other.title == title) && | ||||
|             (identical(other.description, description) || | ||||
|                 other.description == description) && | ||||
|             (identical(other.content, content) || other.content == content) && | ||||
|             (identical(other.url, url) || other.url == url) && | ||||
|             (identical(other.hash, hash) || other.hash == hash) && | ||||
|             (identical(other.source, source) || other.source == source) && | ||||
|             (identical(other.publishedAt, publishedAt) || | ||||
|                 other.publishedAt == publishedAt)); | ||||
|   } | ||||
|  | ||||
|   @JsonKey(includeFromJson: false, includeToJson: false) | ||||
|   @override | ||||
|   int get hashCode => Object.hash( | ||||
|       runtimeType, | ||||
|       id, | ||||
|       createdAt, | ||||
|       updatedAt, | ||||
|       const DeepCollectionEquality().hash(deletedAt), | ||||
|       thumbnail, | ||||
|       title, | ||||
|       description, | ||||
|       content, | ||||
|       url, | ||||
|       hash, | ||||
|       source, | ||||
|       publishedAt); | ||||
|  | ||||
|   /// Create a copy of SnNewsArticle | ||||
|   /// with the given fields replaced by the non-null parameter values. | ||||
|   @JsonKey(includeFromJson: false, includeToJson: false) | ||||
|   @override | ||||
|   @pragma('vm:prefer-inline') | ||||
|   _$$SnNewsArticleImplCopyWith<_$SnNewsArticleImpl> get copyWith => | ||||
|       __$$SnNewsArticleImplCopyWithImpl<_$SnNewsArticleImpl>(this, _$identity); | ||||
|  | ||||
|   @override | ||||
|   Map<String, dynamic> toJson() { | ||||
|     return _$$SnNewsArticleImplToJson( | ||||
|       this, | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| abstract class _SnNewsArticle implements SnNewsArticle { | ||||
|   const factory _SnNewsArticle( | ||||
|       {required final int id, | ||||
|       required final DateTime createdAt, | ||||
|       required final DateTime updatedAt, | ||||
|       required final dynamic deletedAt, | ||||
|       required final String thumbnail, | ||||
|       required final String title, | ||||
|       required final String description, | ||||
|       required final String content, | ||||
|       required final String url, | ||||
|       required final String hash, | ||||
|       required final String source, | ||||
|       required final DateTime? publishedAt}) = _$SnNewsArticleImpl; | ||||
|  | ||||
|   factory _SnNewsArticle.fromJson(Map<String, dynamic> json) = | ||||
|       _$SnNewsArticleImpl.fromJson; | ||||
|  | ||||
|   @override | ||||
|   int get id; | ||||
|   @override | ||||
|   DateTime get createdAt; | ||||
|   @override | ||||
|   DateTime get updatedAt; | ||||
|   @override | ||||
|   dynamic get deletedAt; | ||||
|   @override | ||||
|   String get thumbnail; | ||||
|   @override | ||||
|   String get title; | ||||
|   @override | ||||
|   String get description; | ||||
|   @override | ||||
|   String get content; | ||||
|   @override | ||||
|   String get url; | ||||
|   @override | ||||
|   String get hash; | ||||
|   @override | ||||
|   String get source; | ||||
|   @override | ||||
|   DateTime? get publishedAt; | ||||
|  | ||||
|   /// Create a copy of SnNewsArticle | ||||
|   /// with the given fields replaced by the non-null parameter values. | ||||
|   @override | ||||
|   @JsonKey(includeFromJson: false, includeToJson: false) | ||||
|   _$$SnNewsArticleImplCopyWith<_$SnNewsArticleImpl> get copyWith => | ||||
|       throw _privateConstructorUsedError; | ||||
| } | ||||
							
								
								
									
										61
									
								
								lib/types/news.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								lib/types/news.g.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| // GENERATED CODE - DO NOT MODIFY BY HAND | ||||
|  | ||||
| part of 'news.dart'; | ||||
|  | ||||
| // ************************************************************************** | ||||
| // JsonSerializableGenerator | ||||
| // ************************************************************************** | ||||
|  | ||||
| _$SnNewsSourceImpl _$$SnNewsSourceImplFromJson(Map<String, dynamic> json) => | ||||
|     _$SnNewsSourceImpl( | ||||
|       id: json['id'] as String, | ||||
|       label: json['label'] as String, | ||||
|       type: json['type'] as String, | ||||
|       source: json['source'] as String, | ||||
|       depth: (json['depth'] as num).toInt(), | ||||
|       enabled: json['enabled'] as bool, | ||||
|     ); | ||||
|  | ||||
| Map<String, dynamic> _$$SnNewsSourceImplToJson(_$SnNewsSourceImpl instance) => | ||||
|     <String, dynamic>{ | ||||
|       'id': instance.id, | ||||
|       'label': instance.label, | ||||
|       'type': instance.type, | ||||
|       'source': instance.source, | ||||
|       'depth': instance.depth, | ||||
|       'enabled': instance.enabled, | ||||
|     }; | ||||
|  | ||||
| _$SnNewsArticleImpl _$$SnNewsArticleImplFromJson(Map<String, dynamic> json) => | ||||
|     _$SnNewsArticleImpl( | ||||
|       id: (json['id'] as num).toInt(), | ||||
|       createdAt: DateTime.parse(json['created_at'] as String), | ||||
|       updatedAt: DateTime.parse(json['updated_at'] as String), | ||||
|       deletedAt: json['deleted_at'], | ||||
|       thumbnail: json['thumbnail'] as String, | ||||
|       title: json['title'] as String, | ||||
|       description: json['description'] as String, | ||||
|       content: json['content'] as String, | ||||
|       url: json['url'] as String, | ||||
|       hash: json['hash'] as String, | ||||
|       source: json['source'] as String, | ||||
|       publishedAt: json['published_at'] == null | ||||
|           ? null | ||||
|           : DateTime.parse(json['published_at'] as String), | ||||
|     ); | ||||
|  | ||||
| Map<String, dynamic> _$$SnNewsArticleImplToJson(_$SnNewsArticleImpl instance) => | ||||
|     <String, dynamic>{ | ||||
|       'id': instance.id, | ||||
|       'created_at': instance.createdAt.toIso8601String(), | ||||
|       'updated_at': instance.updatedAt.toIso8601String(), | ||||
|       'deleted_at': instance.deletedAt, | ||||
|       'thumbnail': instance.thumbnail, | ||||
|       'title': instance.title, | ||||
|       'description': instance.description, | ||||
|       'content': instance.content, | ||||
|       'url': instance.url, | ||||
|       'hash': instance.hash, | ||||
|       'source': instance.source, | ||||
|       'published_at': instance.publishedAt?.toIso8601String(), | ||||
|     }; | ||||
| @@ -13,6 +13,7 @@ import file_selector_macos | ||||
| import firebase_analytics | ||||
| import firebase_core | ||||
| import firebase_messaging | ||||
| import flutter_inappwebview_macos | ||||
| import flutter_udid | ||||
| import flutter_webrtc | ||||
| import gal | ||||
| @@ -40,6 +41,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { | ||||
|   FLTFirebaseAnalyticsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAnalyticsPlugin")) | ||||
|   FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) | ||||
|   FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) | ||||
|   InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) | ||||
|   FlutterUdidPlugin.register(with: registry.registrar(forPlugin: "FlutterUdidPlugin")) | ||||
|   FlutterWebRTCPlugin.register(with: registry.registrar(forPlugin: "FlutterWebRTCPlugin")) | ||||
|   GalPlugin.register(with: registry.registrar(forPlugin: "GalPlugin")) | ||||
|   | ||||
							
								
								
									
										66
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										66
									
								
								pubspec.lock
									
									
									
									
									
								
							| @@ -675,6 +675,70 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.3.0" | ||||
|   flutter_inappwebview: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: flutter_inappwebview | ||||
|       sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "6.1.5" | ||||
|   flutter_inappwebview_android: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: flutter_inappwebview_android | ||||
|       sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.1.3" | ||||
|   flutter_inappwebview_internal_annotations: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: flutter_inappwebview_internal_annotations | ||||
|       sha256: "787171d43f8af67864740b6f04166c13190aa74a1468a1f1f1e9ee5b90c359cd" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.2.0" | ||||
|   flutter_inappwebview_ios: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: flutter_inappwebview_ios | ||||
|       sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.1.2" | ||||
|   flutter_inappwebview_macos: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: flutter_inappwebview_macos | ||||
|       sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.1.2" | ||||
|   flutter_inappwebview_platform_interface: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: flutter_inappwebview_platform_interface | ||||
|       sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.3.0+1" | ||||
|   flutter_inappwebview_web: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: flutter_inappwebview_web | ||||
|       sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.1.2" | ||||
|   flutter_inappwebview_windows: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: flutter_inappwebview_windows | ||||
|       sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.6.0" | ||||
|   flutter_launcher_icons: | ||||
|     dependency: "direct dev" | ||||
|     description: | ||||
| @@ -875,7 +939,7 @@ packages: | ||||
|     source: hosted | ||||
|     version: "0.7.0" | ||||
|   html: | ||||
|     dependency: transitive | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: html | ||||
|       sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec" | ||||
|   | ||||
| @@ -115,6 +115,8 @@ dependencies: | ||||
|   slide_countdown: ^2.0.2 | ||||
|   video_compress: ^3.1.3 | ||||
|   cached_network_image: ^3.4.1 | ||||
|   flutter_inappwebview: ^6.1.5 | ||||
|   html: ^0.15.5 | ||||
|  | ||||
| dev_dependencies: | ||||
|   flutter_test: | ||||
|   | ||||
| @@ -16,6 +16,8 @@ | ||||
|     --> | ||||
|     <base href="$FLUTTER_BASE_HREF"> | ||||
|  | ||||
|     <script type="application/javascript" src="/assets/packages/flutter_inappwebview_web/assets/web/web_support.js" defer></script> | ||||
|  | ||||
|     <meta charset="UTF-8"> | ||||
|     <meta content="IE=Edge" http-equiv="X-UA-Compatible"> | ||||
|     <meta name="description" content="A new Flutter project."> | ||||
|   | ||||
| @@ -11,6 +11,7 @@ | ||||
| #include <file_saver/file_saver_plugin.h> | ||||
| #include <file_selector_windows/file_selector_windows.h> | ||||
| #include <firebase_core/firebase_core_plugin_c_api.h> | ||||
| #include <flutter_inappwebview_windows/flutter_inappwebview_windows_plugin_c_api.h> | ||||
| #include <flutter_udid/flutter_udid_plugin_c_api.h> | ||||
| #include <flutter_webrtc/flutter_web_r_t_c_plugin.h> | ||||
| #include <gal/gal_plugin_c_api.h> | ||||
| @@ -34,6 +35,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { | ||||
|       registry->GetRegistrarForPlugin("FileSelectorWindows")); | ||||
|   FirebaseCorePluginCApiRegisterWithRegistrar( | ||||
|       registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); | ||||
|   FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar( | ||||
|       registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi")); | ||||
|   FlutterUdidPluginCApiRegisterWithRegistrar( | ||||
|       registry->GetRegistrarForPlugin("FlutterUdidPluginCApi")); | ||||
|   FlutterWebRTCPluginRegisterWithRegistrar( | ||||
|   | ||||
| @@ -8,6 +8,7 @@ list(APPEND FLUTTER_PLUGIN_LIST | ||||
|   file_saver | ||||
|   file_selector_windows | ||||
|   firebase_core | ||||
|   flutter_inappwebview_windows | ||||
|   flutter_udid | ||||
|   flutter_webrtc | ||||
|   gal | ||||
|   | ||||
		Reference in New Issue
	
	Block a user