Compare commits
	
		
			4 Commits
		
	
	
		
			5377161fb0
			...
			0dcfcaad56
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 0dcfcaad56 | |||
| 687e720956 | |||
| 180876949e | |||
| 9718965809 | 
| @@ -12,6 +12,7 @@ post { | ||||
|  | ||||
| body:json { | ||||
|   { | ||||
|     "sources": ["taiwan-ltn"], | ||||
|     "eager": true | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -564,5 +564,6 @@ | ||||
|   "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." | ||||
|   "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.", | ||||
|   "newsToday": "Today's News" | ||||
| } | ||||
|   | ||||
| @@ -562,5 +562,6 @@ | ||||
|   "newsReadingProviderSwap": "切换", | ||||
|   "newsReadingFromReader": "你正在从 HyperNet.Reader 阅读文章", | ||||
|   "newsReadingFromOriginal": "你正在阅读原始文章", | ||||
|   "newsDisclaimer": "本文由 HyperNet.Reader 从互联网上获取,我们不担保其内容的真实性,请自行判断。本文章的所有内容版权归原作者所有。" | ||||
|   "newsDisclaimer": "本文由 HyperNet.Reader 从互联网上获取,我们不担保其内容的真实性,请自行判断。本文章的所有内容版权归原作者所有。", | ||||
|   "newsToday": "快讯" | ||||
| } | ||||
|   | ||||
| @@ -562,5 +562,6 @@ | ||||
|   "newsReadingProviderSwap": "切換", | ||||
|   "newsReadingFromReader": "你正在從 HyperNet.Reader 閲讀文章", | ||||
|   "newsReadingFromOriginal": "你正在閲讀原始文章", | ||||
|   "newsDisclaimer": "本文由 HyperNet.Reader 從互聯網上獲取,我們不擔保其內容的真實性,請自行判斷。本文章的所有內容版權歸原作者所有。" | ||||
|   "newsDisclaimer": "本文由 HyperNet.Reader 從互聯網上獲取,我們不擔保其內容的真實性,請自行判斷。本文章的所有內容版權歸原作者所有。", | ||||
|   "newsToday": "快訊" | ||||
| } | ||||
|   | ||||
| @@ -562,5 +562,6 @@ | ||||
|   "newsReadingProviderSwap": "切換", | ||||
|   "newsReadingFromReader": "你正在從 HyperNet.Reader 閱讀文章", | ||||
|   "newsReadingFromOriginal": "你正在閱讀原始文章", | ||||
|   "newsDisclaimer": "本文由 HyperNet.Reader 從互聯網上獲取,我們不擔保其內容的真實性,請自行判斷。本文章的所有內容版權歸原作者所有。" | ||||
|   "newsDisclaimer": "本文由 HyperNet.Reader 從互聯網上獲取,我們不擔保其內容的真實性,請自行判斷。本文章的所有內容版權歸原作者所有。", | ||||
|   "newsToday": "快訊" | ||||
| } | ||||
|   | ||||
| @@ -260,7 +260,7 @@ class _AppSplashScreenState extends State<_AppSplashScreen> { | ||||
|     try { | ||||
|       final cfg = context.read<ConfigProvider>(); | ||||
|       WidgetsBinding.instance.addPostFrameCallback((_) { | ||||
|         cfg.calcDrawerSize(context, withMediaQuery: true); | ||||
|         cfg.calcDrawerSize(context); | ||||
|       }); | ||||
|       final home = context.read<HomeWidgetProvider>(); | ||||
|       await home.initialize(); | ||||
|   | ||||
| @@ -50,7 +50,7 @@ class ConfigProvider extends ChangeNotifier { | ||||
|     } else { | ||||
|       final rpb = ResponsiveBreakpoints.of(context); | ||||
|       newDrawerIsCollapsed = rpb.smallerOrEqualTo(MOBILE); | ||||
|       newDrawerIsCollapsed = rpb.largerThan(TABLET) | ||||
|       newDrawerIsExpanded = rpb.largerThan(TABLET) | ||||
|           ? (prefs.getBool(kAppDrawerPreferCollapse) ?? false) | ||||
|               ? false | ||||
|               : true | ||||
|   | ||||
| @@ -9,6 +9,7 @@ import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; | ||||
| import 'package:gap/gap.dart'; | ||||
| import 'package:go_router/go_router.dart'; | ||||
| import 'package:google_fonts/google_fonts.dart'; | ||||
| import 'package:html/parser.dart'; | ||||
| import 'package:material_symbols_icons/symbols.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
| import 'package:relative_time/relative_time.dart'; | ||||
| @@ -22,6 +23,7 @@ import 'package:surface/providers/special_day.dart'; | ||||
| import 'package:surface/providers/userinfo.dart'; | ||||
| import 'package:surface/providers/widget.dart'; | ||||
| import 'package:surface/types/check_in.dart'; | ||||
| import 'package:surface/types/news.dart'; | ||||
| import 'package:surface/types/post.dart'; | ||||
| import 'package:surface/widgets/app_bar_leading.dart'; | ||||
| import 'package:surface/widgets/dialog.dart'; | ||||
| @@ -52,9 +54,9 @@ class _HomeScreenState extends State<HomeScreen> { | ||||
|   static const List<HomeScreenDashEntry> kCards = [ | ||||
|     HomeScreenDashEntry( | ||||
|       name: 'dashEntryRecommendation', | ||||
|       cols: 2, | ||||
|       rows: 2, | ||||
|       child: _HomeDashRecommendationPostWidget(), | ||||
|       rows: 2, | ||||
|       cols: 2, | ||||
|     ), | ||||
|     HomeScreenDashEntry( | ||||
|       name: 'dashEntryCheckIn', | ||||
| @@ -64,6 +66,11 @@ class _HomeScreenState extends State<HomeScreen> { | ||||
|       name: 'dashEntryNotification', | ||||
|       child: _HomeDashNotificationWidget(), | ||||
|     ), | ||||
|     HomeScreenDashEntry( | ||||
|       name: 'dashEntryTodayNews', | ||||
|       child: _HomeDashTodayNews(), | ||||
|       cols: 2, | ||||
|     ), | ||||
|   ]; | ||||
|  | ||||
|   @override | ||||
| @@ -230,6 +237,107 @@ class _HomeDashSpecialDayWidgetState extends State<_HomeDashSpecialDayWidget> { | ||||
|   } | ||||
| } | ||||
|  | ||||
| class _HomeDashTodayNews extends StatefulWidget { | ||||
|   const _HomeDashTodayNews(); | ||||
|  | ||||
|   @override | ||||
|   State<_HomeDashTodayNews> createState() => _HomeDashTodayNewsState(); | ||||
| } | ||||
|  | ||||
| class _HomeDashTodayNewsState extends State<_HomeDashTodayNews> { | ||||
|   SnNewsArticle? _article; | ||||
|  | ||||
|   Future<void> _fetchArticle() async { | ||||
|     try { | ||||
|       final sn = context.read<SnNetworkProvider>(); | ||||
|       final resp = await sn.client.get('/cgi/re/news/today'); | ||||
|       _article = SnNewsArticle.fromJson(resp.data['data']); | ||||
|     } catch (err) { | ||||
|       if (!mounted) return; | ||||
|       context.showErrorDialog(err); | ||||
|       rethrow; | ||||
|     } finally { | ||||
|       setState(() {}); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   initState() { | ||||
|     super.initState(); | ||||
|     _fetchArticle(); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Card( | ||||
|       child: Column( | ||||
|         crossAxisAlignment: CrossAxisAlignment.start, | ||||
|         children: [ | ||||
|           Row( | ||||
|             children: [ | ||||
|               const Icon(Symbols.newspaper), | ||||
|               const Gap(8), | ||||
|               Text( | ||||
|                 'newsToday', | ||||
|                 style: Theme.of(context).textTheme.titleLarge, | ||||
|               ).tr() | ||||
|             ], | ||||
|           ).padding(horizontal: 18, top: 12, bottom: 8), | ||||
|           if (_article != null) | ||||
|             Expanded( | ||||
|               child: InkWell( | ||||
|                 borderRadius: BorderRadius.all(Radius.circular(8)), | ||||
|                 child: Column( | ||||
|                   spacing: 4, | ||||
|                   children: [ | ||||
|                     Text( | ||||
|                       _article!.title, | ||||
|                       style: Theme.of(context).textTheme.titleMedium!.copyWith(fontSize: 18), | ||||
|                       maxLines: 2, | ||||
|                       overflow: TextOverflow.ellipsis, | ||||
|                     ), | ||||
|                     Text( | ||||
|                       parse(_article!.description).children.map((e) => e.text.trim()).join(), | ||||
|                       maxLines: 3, | ||||
|                       overflow: TextOverflow.ellipsis, | ||||
|                       style: Theme.of(context).textTheme.bodyMedium, | ||||
|                     ), | ||||
|                     Builder( | ||||
|                       builder: (context) { | ||||
|                         final date = _article!.publishedAt ?? _article!.createdAt; | ||||
|                         return Row( | ||||
|                           crossAxisAlignment: CrossAxisAlignment.center, | ||||
|                           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), | ||||
|                 onTap: () { | ||||
|                   GoRouter.of(context).pushNamed( | ||||
|                     'newsDetail', | ||||
|                     pathParameters: {'hash': _article!.hash}, | ||||
|                   ); | ||||
|                 }, | ||||
|               ), | ||||
|             ) | ||||
|           else | ||||
|             Expanded( | ||||
|               child: Center( | ||||
|                 child: CircularProgressIndicator(), | ||||
|               ), | ||||
|             ) | ||||
|         ], | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class _HomeDashCheckInWidget extends StatefulWidget { | ||||
|   const _HomeDashCheckInWidget(); | ||||
|  | ||||
|   | ||||
| @@ -101,7 +101,9 @@ class _NewsDetailScreenState extends State<NewsDetailScreen> { | ||||
|           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')) { | ||||
|           if (src.startsWith('//')) { | ||||
|             src = 'https:$src'; | ||||
|           } else if (!src.startsWith('http')) { | ||||
|             final baseUri = Uri.parse(_article!.url); | ||||
|             final baseUrl = '${baseUri.scheme}://${baseUri.host}'; | ||||
|             src = '$baseUrl/$src'; | ||||
| @@ -120,7 +122,13 @@ class _NewsDetailScreenState extends State<NewsDetailScreen> { | ||||
|                 height: height ?? double.infinity, | ||||
|                 child: ClipRRect( | ||||
|                   borderRadius: BorderRadius.all(Radius.circular(8)), | ||||
|                   child: AutoResizeUniversalImage(src, fit: BoxFit.cover), | ||||
|                   child: Container( | ||||
|                     color: Theme.of(context).colorScheme.surfaceContainer, | ||||
|                     child: AutoResizeUniversalImage( | ||||
|                       src, | ||||
|                       fit: width != null && height != null ? BoxFit.cover : BoxFit.contain, | ||||
|                     ), | ||||
|                   ), | ||||
|                 ), | ||||
|               ), | ||||
|             ), | ||||
|   | ||||
| @@ -178,11 +178,17 @@ class _NewsArticleListWidgetState extends State<_NewsArticleListWidget> { | ||||
|                   children: [ | ||||
|                     if (article.thumbnail.isNotEmpty && !article.thumbnail.endsWith('.svg')) | ||||
|                       ClipRRect( | ||||
|                         borderRadius: BorderRadius.all(Radius.circular(8)), | ||||
|                         borderRadius: BorderRadius.only( | ||||
|                           topRight: Radius.circular(8), | ||||
|                           topLeft: Radius.circular(8), | ||||
|                         ), | ||||
|                         child: AspectRatio( | ||||
|                           aspectRatio: 16 / 9, | ||||
|                           child: AutoResizeUniversalImage( | ||||
|                             article.thumbnail.startsWith('http') ? article.thumbnail : '$baseUrl/${article.thumbnail}', | ||||
|                           child: Container( | ||||
|                             color: Theme.of(context).colorScheme.surfaceContainer, | ||||
|                             child: AutoResizeUniversalImage( | ||||
|                               article.thumbnail.startsWith('http') ? article.thumbnail : '$baseUrl/${article.thumbnail}', | ||||
|                             ), | ||||
|                           ), | ||||
|                         ), | ||||
|                       ), | ||||
|   | ||||
| @@ -72,6 +72,9 @@ PODS: | ||||
|     - GoogleUtilities/Reachability (~> 8.0) | ||||
|     - GoogleUtilities/UserDefaults (~> 8.0) | ||||
|     - nanopb (~> 3.30910.0) | ||||
|   - flutter_inappwebview_macos (0.0.1): | ||||
|     - FlutterMacOS | ||||
|     - OrderedSet (~> 6.0.3) | ||||
|   - flutter_udid (0.0.1): | ||||
|     - FlutterMacOS | ||||
|     - SAMKeychain | ||||
| @@ -149,6 +152,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.0.1): | ||||
|     - FlutterMacOS | ||||
|   - pasteboard (0.0.1): | ||||
| @@ -186,6 +190,7 @@ DEPENDENCIES: | ||||
|   - firebase_analytics (from `Flutter/ephemeral/.symlinks/plugins/firebase_analytics/macos`) | ||||
|   - firebase_core (from `Flutter/ephemeral/.symlinks/plugins/firebase_core/macos`) | ||||
|   - firebase_messaging (from `Flutter/ephemeral/.symlinks/plugins/firebase_messaging/macos`) | ||||
|   - flutter_inappwebview_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_inappwebview_macos/macos`) | ||||
|   - flutter_udid (from `Flutter/ephemeral/.symlinks/plugins/flutter_udid/macos`) | ||||
|   - flutter_webrtc (from `Flutter/ephemeral/.symlinks/plugins/flutter_webrtc/macos`) | ||||
|   - FlutterMacOS (from `Flutter/ephemeral`) | ||||
| @@ -218,6 +223,7 @@ SPEC REPOS: | ||||
|     - GoogleDataTransport | ||||
|     - GoogleUtilities | ||||
|     - nanopb | ||||
|     - OrderedSet | ||||
|     - PromisesObjC | ||||
|     - SAMKeychain | ||||
|     - WebRTC-SDK | ||||
| @@ -241,6 +247,8 @@ EXTERNAL SOURCES: | ||||
|     :path: Flutter/ephemeral/.symlinks/plugins/firebase_core/macos | ||||
|   firebase_messaging: | ||||
|     :path: Flutter/ephemeral/.symlinks/plugins/firebase_messaging/macos | ||||
|   flutter_inappwebview_macos: | ||||
|     :path: Flutter/ephemeral/.symlinks/plugins/flutter_inappwebview_macos/macos | ||||
|   flutter_udid: | ||||
|     :path: Flutter/ephemeral/.symlinks/plugins/flutter_udid/macos | ||||
|   flutter_webrtc: | ||||
| @@ -296,6 +304,7 @@ SPEC CHECKSUMS: | ||||
|   FirebaseCoreInternal: d98ab91e2d80a56d7b246856a8885443b302c0c2 | ||||
|   FirebaseInstallations: efc0946fc756e4d22d8113f7c761948120322e8c | ||||
|   FirebaseMessaging: e1aca1fcc23e8b9eddb0e33f375ff90944623021 | ||||
|   flutter_inappwebview_macos: bdf207b8f4ebd58e86ae06cd96b147de99a67c9b | ||||
|   flutter_udid: 2e7b3da4b5fdfba86a396b97898f5fe8f4ec1a52 | ||||
|   flutter_webrtc: d55fd3f5c75b42940b6b4b2cf376a5797398d1f8 | ||||
|   FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 | ||||
| @@ -309,6 +318,7 @@ SPEC CHECKSUMS: | ||||
|   media_kit_native_event_loop: 81fd5b45192b72f8b5b69eaf5b540f45777eb8d5 | ||||
|   media_kit_video: c75b07f14d59706c775778e4dd47dd027de8d1e5 | ||||
|   nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 | ||||
|   OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 | ||||
|   package_info_plus: 12f1c5c2cfe8727ca46cbd0b26677728972d9a5b | ||||
|   pasteboard: 9b69dba6fedbb04866be632205d532fe2f6b1d99 | ||||
|   path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 | ||||
|   | ||||
| @@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev | ||||
| # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html | ||||
| # In Windows, build-name is used as the major, minor, and patch parts | ||||
| # of the product and file versions while build-number is used as the build suffix. | ||||
| version: 2.2.2+56 | ||||
| version: 2.2.2+57 | ||||
|  | ||||
| environment: | ||||
|   sdk: ^3.5.4 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user