~cytrogen/fluent-reader-mobile

db17140569bfa3aa542322dbb3c76e7b5fb7d97f — Bruce Liu 2 years ago 7629f7f
update dependencies
A .vscode/settings.json => .vscode/settings.json +3 -0
@@ 0,0 1,3 @@
{
    "java.configuration.updateBuildConfiguration": "interactive"
}
\ No newline at end of file

M android/app/build.gradle => android/app/build.gradle +2 -2
@@ 32,7 32,7 @@ if (keystorePropertiesFile.exists()) {
}

android {
    compileSdkVersion 31
    compileSdkVersion 33

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'


@@ 46,7 46,7 @@ android {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "me.hyliu.fluent_reader_lite"
        minSdkVersion 24
        targetSdkVersion 29
        targetSdkVersion 33
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }

M android/app/src/main/AndroidManifest.xml => android/app/src/main/AndroidManifest.xml +2 -1
@@ 19,7 19,8 @@
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            android:windowSoftInputMode="adjustResize"
            android:exported="true">
            <!-- Specifies an Android theme to apply to this Activity as soon as
                 the Android process has started. This theme is visible to the user
                 while the Flutter UI initializes. After that, this theme continues

M android/gradle/wrapper/gradle-wrapper.properties => android/gradle/wrapper/gradle-wrapper.properties +1 -2
@@ 1,6 1,5 @@
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip

M ios/Podfile => ios/Podfile +1 -1
@@ 1,5 1,5 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'
platform :ios, '11.0'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

M ios/Podfile.lock => ios/Podfile.lock +17 -15
@@ 5,13 5,15 @@ PODS:
  - FMDB/standard (2.7.5)
  - package_info (0.0.1):
    - Flutter
  - path_provider_ios (0.0.1):
  - path_provider_foundation (0.0.1):
    - Flutter
    - FlutterMacOS
  - share (0.0.1):
    - Flutter
  - shared_preferences_ios (0.0.1):
  - shared_preferences_foundation (0.0.1):
    - Flutter
  - sqflite (0.0.2):
    - FlutterMacOS
  - sqflite (0.0.3):
    - Flutter
    - FMDB (>= 2.7.5)
  - uni_links (0.0.1):


@@ 24,9 26,9 @@ PODS:
DEPENDENCIES:
  - Flutter (from `Flutter`)
  - package_info (from `.symlinks/plugins/package_info/ios`)
  - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
  - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`)
  - share (from `.symlinks/plugins/share/ios`)
  - shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
  - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`)
  - sqflite (from `.symlinks/plugins/sqflite/ios`)
  - uni_links (from `.symlinks/plugins/uni_links/ios`)
  - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)


@@ 41,12 43,12 @@ EXTERNAL SOURCES:
    :path: Flutter
  package_info:
    :path: ".symlinks/plugins/package_info/ios"
  path_provider_ios:
    :path: ".symlinks/plugins/path_provider_ios/ios"
  path_provider_foundation:
    :path: ".symlinks/plugins/path_provider_foundation/ios"
  share:
    :path: ".symlinks/plugins/share/ios"
  shared_preferences_ios:
    :path: ".symlinks/plugins/shared_preferences_ios/ios"
  shared_preferences_foundation:
    :path: ".symlinks/plugins/shared_preferences_foundation/ios"
  sqflite:
    :path: ".symlinks/plugins/sqflite/ios"
  uni_links:


@@ 57,17 59,17 @@ EXTERNAL SOURCES:
    :path: ".symlinks/plugins/webview_flutter_wkwebview/ios"

SPEC CHECKSUMS:
  Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
  Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
  FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
  package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
  path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02
  path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
  share: 0b2c3e82132f5888bccca3351c504d0003b3b410
  shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad
  sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
  shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
  sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
  uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
  url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de
  url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
  webview_flutter_wkwebview: b7e70ef1ddded7e69c796c7390ee74180182971f

PODFILE CHECKSUM: c228b831dc9a93a7cc7fac97cfb31e9d63a09fc8
PODFILE CHECKSUM: 376096882d437f9c058954415163c2a0ff42c27b

COCOAPODS: 1.11.3

M ios/Runner.xcodeproj/project.pbxproj => ios/Runner.xcodeproj/project.pbxproj +3 -1
@@ 3,7 3,7 @@
	archiveVersion = 1;
	classes = {
	};
	objectVersion = 51;
	objectVersion = 54;
	objects = {

/* Begin PBXBuildFile section */


@@ 237,6 237,7 @@
		};
		3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
			isa = PBXShellScriptBuildPhase;
			alwaysOutOfDate = 1;
			buildActionMask = 2147483647;
			files = (
			);


@@ 251,6 252,7 @@
		};
		9740EEB61CF901F6004384FC /* Run Script */ = {
			isa = PBXShellScriptBuildPhase;
			alwaysOutOfDate = 1;
			buildActionMask = 2147483647;
			files = (
			);

M ios/Runner/Info.plist => ios/Runner/Info.plist +2 -0
@@ 65,5 65,7 @@
	<true/>
	<key>CADisableMinimumFrameDurationOnPhone</key>
	<true/>
	<key>UIApplicationSupportsIndirectInputEvents</key>
	<true/>
</dict>
</plist>

M lib/components/subscription_item.dart => lib/components/subscription_item.dart +51 -29
@@ 5,7 5,7 @@ import 'package:fluent_reader_lite/components/time_text.dart';
import 'package:fluent_reader_lite/models/source.dart';
import 'package:fluent_reader_lite/utils/global.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/material.dart' hide Badge;
import 'package:flutter/services.dart';

import 'badge.dart';


@@ 72,7 72,11 @@ class _SubscriptionItemState extends State<SubscriptionItem> {
              child: Favicon(widget.source),
            ),
            Expanded(
              child: Text(widget.source.name, style: _titleStyle, overflow: TextOverflow.ellipsis,),
              child: Text(
                widget.source.name,
                style: _titleStyle,
                overflow: TextOverflow.ellipsis,
              ),
            ),
          ]),
        ),


@@ 83,47 87,65 @@ class _SubscriptionItemState extends State<SubscriptionItem> {
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: [
        Expanded(
          child: Text(widget.source.lastTitle, style: _descStyle, overflow: TextOverflow.ellipsis),
          child: Text(widget.source.lastTitle,
              style: _descStyle, overflow: TextOverflow.ellipsis),
        ),
        if (widget.source.unreadCount > 0) Badge(widget.source.unreadCount),
      ],
    );
    final body = GestureDetector(
      onTapDown: (_) { setState(() { pressed = true; }); },
      onTapUp: (_) { setState(() { pressed = false; }); },
      onTapCancel: () { setState(() { pressed = false; }); },
      onTapDown: (_) {
        setState(() {
          pressed = true;
        });
      },
      onTapUp: (_) {
        setState(() {
          pressed = false;
        });
      },
      onTapCancel: () {
        setState(() {
          pressed = false;
        });
      },
      onTap: _openSourcePage,
      child: Column(children: [
        Container(
          constraints: BoxConstraints(minHeight: 64),
          color: pressed 
            ? CupertinoColors.systemGrey4.resolveFrom(context) 
            : CupertinoColors.systemBackground.resolveFrom(context),
          child: Padding(
            padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                topLine,
                Padding(padding: EdgeInsets.only(top: 4)),
                bottomLine
              ],
      child: Column(
        children: [
          Container(
            constraints: BoxConstraints(minHeight: 64),
            color: pressed
                ? CupertinoColors.systemGrey4.resolveFrom(context)
                : CupertinoColors.systemBackground.resolveFrom(context),
            child: Padding(
              padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  topLine,
                  Padding(padding: EdgeInsets.only(top: 4)),
                  bottomLine
                ],
              ),
            ),
          ),
        ),
        Padding(
          padding: EdgeInsets.only(left: 16),
          child: Divider(color: CupertinoColors.systemGrey4.resolveFrom(context), height: 1),
        ),
      ],),
          Padding(
            padding: EdgeInsets.only(left: 16),
            child: Divider(
                color: CupertinoColors.systemGrey4.resolveFrom(context),
                height: 1),
          ),
        ],
      ),
    );
    return Dismissible(
      key: Key("D-${widget.source.id}"),
      background: DismissibleBackground(CupertinoIcons.checkmark_circle, true),
      secondaryBackground: DismissibleBackground(CupertinoIcons.pencil_circle, false),
      secondaryBackground:
          DismissibleBackground(CupertinoIcons.pencil_circle, false),
      dismissThresholds: _dismissThresholds,
      confirmDismiss: _onDismiss,
      child: body,
    );
  }
}
\ No newline at end of file
}

M lib/main.dart => lib/main.dart +6 -1
@@ 135,7 135,12 @@ class MyApp extends StatelessWidget {
            brightness: globalModel.getBrightness(),
          ),
          routes: {
            "/": (context) => CupertinoScaffold(body: HomePage()),
            "/": (context) => CupertinoScaffold(
                body: CupertinoTheme(
                    // For fixing the bug with modal_bottom_sheet overriding primary color
                    data: CupertinoThemeData(
                        primaryColor: CupertinoColors.activeBlue),
                    child: HomePage())),
            ...baseRoutes,
          },
          builder: (context, child) {

M lib/pages/item_list_page.dart => lib/pages/item_list_page.dart +177 -165
@@ 13,7 13,7 @@ import 'package:fluent_reader_lite/models/sources_model.dart';
import 'package:fluent_reader_lite/pages/settings/text_editor_page.dart';
import 'package:fluent_reader_lite/utils/global.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/material.dart' hide Badge;
import 'package:provider/provider.dart';
import 'package:share/share.dart';
import 'package:tuple/tuple.dart';


@@ 48,7 48,7 @@ class _ItemListPageState extends State<ItemListPage> {
    super.initState();
    widget.scrollTopNotifier.addListener(_onScrollTop);
  }
  

  @override
  void dispose() {
    widget.scrollTopNotifier.removeListener(_onScrollTop);


@@ 57,19 57,22 @@ class _ItemListPageState extends State<ItemListPage> {

  RSSFeed getFeed() {
    return ModalRoute.of(context).settings.arguments != null
     ? Global.feedsModel.source
     : Global.feedsModel.all;
        ? Global.feedsModel.source
        : Global.feedsModel.all;
  }

  bool _onScroll(ScrollNotification scrollInfo) {
    var feed = getFeed();
    if (!ModalRoute.of(context).isCurrent
      || !feed.initialized || feed.loading || feed.allLoaded) {
    if (!ModalRoute.of(context).isCurrent ||
        !feed.initialized ||
        feed.loading ||
        feed.allLoaded) {
      return true;
    }
    if (scrollInfo.metrics.extentAfter == 0.0 &&
      scrollInfo.metrics.pixels >= scrollInfo.metrics.maxScrollExtent * 0.8 &&
      (lastLoadedMore == null || DateTime.now().difference(lastLoadedMore).inSeconds > 1)) {
        scrollInfo.metrics.pixels >= scrollInfo.metrics.maxScrollExtent * 0.8 &&
        (lastLoadedMore == null ||
            DateTime.now().difference(lastLoadedMore).inSeconds > 1)) {
      lastLoadedMore = DateTime.now();
      feed.loadMore();
    }


@@ 87,84 90,88 @@ class _ItemListPageState extends State<ItemListPage> {

  void _openFilterModal() {
    showCupertinoModalPopup(
      context: context,
      builder: (context) {
        final feed = getFeed();
        final sheet = CupertinoActionSheet(
          title: Text(S.of(context).filter),
          actions: [
            CupertinoActionSheetAction(
              child: Row(children: [
                Icon(CupertinoIcons.today),
                Text(S.of(context).allArticles),
                _iconPadding,
              ], mainAxisAlignment: MainAxisAlignment.spaceBetween),
              onPressed: () { 
                Navigator.of(context, rootNavigator: true).pop();
                feed.setFilter(FilterType.All);
                _onScrollTop();
              },
            ),
            CupertinoActionSheetAction(
              child: Row(children: [
                Icon(Icons.radio_button_checked),
                Text(S.of(context).unreadOnly),
                _iconPadding,
              ], mainAxisAlignment: MainAxisAlignment.spaceBetween),
              onPressed: () { 
                Navigator.of(context, rootNavigator: true).pop();
                feed.setFilter(FilterType.Unread);
                _onScrollTop();
              },
            ),
            CupertinoActionSheetAction(
              child: Row(children: [
                Icon(CupertinoIcons.star_fill),
                Text(S.of(context).starredOnly),
                _iconPadding,
              ], mainAxisAlignment: MainAxisAlignment.spaceBetween),
              onPressed: () { 
                Navigator.of(context, rootNavigator: true).pop();
                feed.setFilter(FilterType.Starred);
                _onScrollTop();
              },
            ),
            CupertinoActionSheetAction(
              isDestructiveAction: true,
              child: Row(children: [
                Icon(CupertinoIcons.search, color: CupertinoColors.destructiveRed),
                Text(feed.search.length > 0 ? S.of(context).editKeyword : S.of(context).search),
                _iconPadding,
              ], mainAxisAlignment: MainAxisAlignment.spaceBetween),
              onPressed: () { 
                Navigator.of(context, rootNavigator: true).pop();
                _editSearchKeyword();
              },
            ),
            if (feed.search.length > 0) CupertinoActionSheetAction(
              isDestructiveAction: true,
              child: Row(children: [
                Icon(CupertinoIcons.clear_fill, color: CupertinoColors.destructiveRed),
                Text(S.of(context).clearSearch),
                _iconPadding,
              ], mainAxisAlignment: MainAxisAlignment.spaceBetween),
              onPressed: () { 
        context: context,
        builder: (context) {
          final feed = getFeed();
          final sheet = CupertinoActionSheet(
            title: Text(S.of(context).filter),
            actions: [
              CupertinoActionSheetAction(
                child: Row(children: [
                  Icon(CupertinoIcons.today),
                  Text(S.of(context).allArticles),
                  _iconPadding,
                ], mainAxisAlignment: MainAxisAlignment.spaceBetween),
                onPressed: () {
                  Navigator.of(context, rootNavigator: true).pop();
                  feed.setFilter(FilterType.All);
                  _onScrollTop();
                },
              ),
              CupertinoActionSheetAction(
                child: Row(children: [
                  Icon(Icons.radio_button_checked),
                  Text(S.of(context).unreadOnly),
                  _iconPadding,
                ], mainAxisAlignment: MainAxisAlignment.spaceBetween),
                onPressed: () {
                  Navigator.of(context, rootNavigator: true).pop();
                  feed.setFilter(FilterType.Unread);
                  _onScrollTop();
                },
              ),
              CupertinoActionSheetAction(
                child: Row(children: [
                  Icon(CupertinoIcons.star_fill),
                  Text(S.of(context).starredOnly),
                  _iconPadding,
                ], mainAxisAlignment: MainAxisAlignment.spaceBetween),
                onPressed: () {
                  Navigator.of(context, rootNavigator: true).pop();
                  feed.setFilter(FilterType.Starred);
                  _onScrollTop();
                },
              ),
              CupertinoActionSheetAction(
                isDestructiveAction: true,
                child: Row(children: [
                  Icon(CupertinoIcons.search,
                      color: CupertinoColors.destructiveRed),
                  Text(feed.search.length > 0
                      ? S.of(context).editKeyword
                      : S.of(context).search),
                  _iconPadding,
                ], mainAxisAlignment: MainAxisAlignment.spaceBetween),
                onPressed: () {
                  Navigator.of(context, rootNavigator: true).pop();
                  _editSearchKeyword();
                },
              ),
              if (feed.search.length > 0)
                CupertinoActionSheetAction(
                  isDestructiveAction: true,
                  child: Row(children: [
                    Icon(CupertinoIcons.clear_fill,
                        color: CupertinoColors.destructiveRed),
                    Text(S.of(context).clearSearch),
                    _iconPadding,
                  ], mainAxisAlignment: MainAxisAlignment.spaceBetween),
                  onPressed: () {
                    Navigator.of(context, rootNavigator: true).pop();
                    feed.performSearch("");
                    _onScrollTop();
                  },
                ),
            ],
            cancelButton: CupertinoActionSheetAction(
              child: Text(S.of(context).cancel),
              onPressed: () {
                Navigator.of(context, rootNavigator: true).pop();
                feed.performSearch("");
                _onScrollTop();
              },
            ),
          ],
          cancelButton: CupertinoActionSheetAction(
            child: Text(S.of(context).cancel),
            onPressed: () { 
              Navigator.of(context, rootNavigator: true).pop();
            },
          ),
        );
        return ResponsiveActionSheet(sheet);
      }
    );
          );
          return ResponsiveActionSheet(sheet);
        });
  }

  void _editSearchKeyword() async {


@@ 191,22 198,28 @@ class _ItemListPageState extends State<ItemListPage> {
          actions: [
            CupertinoActionSheetAction(
              child: Row(children: [
                Icon(item.hasRead ? Icons.radio_button_checked : Icons.radio_button_unchecked),
                Text(item.hasRead ? S.of(context).markUnread : S.of(context).markRead),
                Icon(item.hasRead
                    ? Icons.radio_button_checked
                    : Icons.radio_button_unchecked),
                Text(item.hasRead
                    ? S.of(context).markUnread
                    : S.of(context).markRead),
                _iconPadding,
              ], mainAxisAlignment: MainAxisAlignment.spaceBetween),
              onPressed: () { 
              onPressed: () {
                Navigator.of(context, rootNavigator: true).pop();
                Global.itemsModel.updateItem(item.id, read: !item.hasRead);
              },
            ),
            CupertinoActionSheetAction(
              child: Row(children: [
                Icon(item.starred ? CupertinoIcons.star : CupertinoIcons.star_fill),
                Icon(item.starred
                    ? CupertinoIcons.star
                    : CupertinoIcons.star_fill),
                Text(item.starred ? S.of(context).unstar : S.of(context).star),
                _iconPadding,
              ], mainAxisAlignment: MainAxisAlignment.spaceBetween),
              onPressed: () { 
              onPressed: () {
                Navigator.of(context, rootNavigator: true).pop();
                Global.itemsModel.updateItem(item.id, starred: !item.starred);
              },


@@ 217,9 230,10 @@ class _ItemListPageState extends State<ItemListPage> {
                Text(S.of(context).markAbove),
                _iconPadding,
              ], mainAxisAlignment: MainAxisAlignment.spaceBetween),
              onPressed: () { 
              onPressed: () {
                Navigator.of(context, rootNavigator: true).pop();
                Global.itemsModel.markAllRead(getFeed().sids, date: item.date, before: false);
                Global.itemsModel.markAllRead(getFeed().sids,
                    date: item.date, before: false);
              },
            ),
            CupertinoActionSheetAction(


@@ 228,7 242,7 @@ class _ItemListPageState extends State<ItemListPage> {
                Text(S.of(context).markBelow),
                _iconPadding,
              ], mainAxisAlignment: MainAxisAlignment.spaceBetween),
              onPressed: () { 
              onPressed: () {
                Navigator.of(context, rootNavigator: true).pop();
                Global.itemsModel.markAllRead(getFeed().sids, date: item.date);
              },


@@ 239,21 253,20 @@ class _ItemListPageState extends State<ItemListPage> {
                Text(S.of(context).share),
                _iconPadding,
              ], mainAxisAlignment: MainAxisAlignment.spaceBetween),
              onPressed: () { 
              onPressed: () {
                Navigator.of(context, rootNavigator: true).pop();
                final media = MediaQuery.of(context);
                Share.share(
                  item.link,
                  sharePositionOrigin: Rect.fromLTWH(
                    160, media.size.height - media.padding.bottom, 0, 0
                  ),
                      160, media.size.height - media.padding.bottom, 0, 0),
                );
              },
            ),
          ],
          cancelButton: CupertinoActionSheetAction(
            child: Text(S.of(context).cancel),
            onPressed: () { 
            onPressed: () {
              Navigator.of(context, rootNavigator: true).pop();
            },
          ),


@@ 264,22 277,22 @@ class _ItemListPageState extends State<ItemListPage> {
  }

  Widget _titleFromFilter() => Consumer<FeedsModel>(
    builder: (context, feedsModel, child) {
      String text;
      switch (getFeed().filterType) {
        case FilterType.Unread:
          text = S.of(context).unread;
          break;
        case FilterType.Starred:
          text = S.of(context).starred;
          break;
        default:
          text = S.of(context).all;
          break;
      }
      return Text(text, overflow: TextOverflow.ellipsis);
    },
  );
        builder: (context, feedsModel, child) {
          String text;
          switch (getFeed().filterType) {
            case FilterType.Unread:
              text = S.of(context).unread;
              break;
            case FilterType.Starred:
              text = S.of(context).starred;
              break;
            default:
              text = S.of(context).all;
              break;
          }
          return Text(text, overflow: TextOverflow.ellipsis);
        },
      );

  @override
  Widget build(BuildContext context) {


@@ 289,14 302,15 @@ class _ItemListPageState extends State<ItemListPage> {
      children: [
        Container(
          constraints: BoxConstraints(
            maxWidth: Global.isTablet
              ? 260
              : MediaQuery.of(context).size.width - 60,
          ),
          child: title == null ? _titleFromFilter() : Text(
            title, 
            overflow: TextOverflow.ellipsis,
            maxWidth:
                Global.isTablet ? 260 : MediaQuery.of(context).size.width - 60,
          ),
          child: title == null
              ? _titleFromFilter()
              : Text(
                  title,
                  overflow: TextOverflow.ellipsis,
                ),
        ),
        Consumer<SourcesModel>(
          builder: (context, sourcesModel, child) {


@@ 318,16 332,14 @@ class _ItemListPageState extends State<ItemListPage> {
      ],
    );
    final navigationBar = CupertinoSliverNavigationBar(
      stretch: false,
      heroTag: title != null ? "source" : "all",
      transitionBetweenRoutes: true,
      backgroundColor: CupertinoColors.systemBackground,
      largeTitle: titleWidget,
      trailing: Container(
        transform: Matrix4.translationValues(12, 0, 0),
        child: Row(
          mainAxisSize: MainAxisSize.min,
          children: [
        stretch: false,
        heroTag: title != null ? "source" : "all",
        transitionBetweenRoutes: true,
        backgroundColor: CupertinoColors.systemBackground,
        largeTitle: titleWidget,
        trailing: Container(
          transform: Matrix4.translationValues(12, 0, 0),
          child: Row(mainAxisSize: MainAxisSize.min, children: [
            CupertinoButton(
              padding: EdgeInsets.zero,
              child: Icon(


@@ 341,64 353,64 @@ class _ItemListPageState extends State<ItemListPage> {
                var feed = getFeed();
                return CupertinoButton(
                  padding: EdgeInsets.zero,
                  child: Icon((feed.filterType != FilterType.All || feed.search.length > 0)
                    ? CupertinoIcons.line_horizontal_3_decrease_circle_fill
                    : CupertinoIcons.line_horizontal_3_decrease_circle,
                  child: Icon(
                    (feed.filterType != FilterType.All ||
                            feed.search.length > 0)
                        ? CupertinoIcons.line_horizontal_3_decrease_circle_fill
                        : CupertinoIcons.line_horizontal_3_decrease_circle,
                    semanticLabel: S.of(context).filter,
                  ),
                  onPressed: _openFilterModal,
                );
              },
            ),
          ]
        ),
      )
    );
          ]),
        ));
    final subscriptionList = Consumer<FeedsModel>(
      builder: (context, feedsModel, child) {
        var feed = getFeed();
        return SliverList(
          delegate: SliverChildBuilderDelegate((content, index) {
            return Selector2<ItemsModel, SourcesModel, Tuple2<RSSItem, RSSSource>>(
            return Selector2<ItemsModel, SourcesModel,
                Tuple2<RSSItem, RSSSource>>(
              selector: (context, itemsModel, sourcesModel) {
                var item = itemsModel.getItem(feed.iids[index]);
                var source = sourcesModel.getSource(item.source);
                return Tuple2(item, source);
              },
              builder: (context, tuple, child) => ArticleItem(
                tuple.item1, tuple.item2, _openActionSheet
              ),
              builder: (context, tuple, child) =>
                  ArticleItem(tuple.item1, tuple.item2, _openActionSheet),
            );
          }, childCount: feed.iids.length),
        );
      },
    );
    final loadMoreIndicator = Consumer<FeedsModel>(
      builder: (context, feedsModel, child) {
        var feed = getFeed();
        return SliverToBoxAdapter(child: Padding(
          padding: EdgeInsets.symmetric(vertical: 20),
          child: Center(
    final loadMoreIndicator =
        Consumer<FeedsModel>(builder: (context, feedsModel, child) {
      var feed = getFeed();
      return SliverToBoxAdapter(
          child: Padding(
        padding: EdgeInsets.symmetric(vertical: 20),
        child: Center(
            child: feed.allLoaded
              ? Text(S.of(context).allLoaded, style: TextStyle(
                  color: CupertinoColors.tertiaryLabel.resolveFrom(context),
                ))
              : CupertinoActivityIndicator()
          ),
        ));
      }
    );
                ? Text(S.of(context).allLoaded,
                    style: TextStyle(
                      color: CupertinoColors.tertiaryLabel.resolveFrom(context),
                    ))
                : CupertinoActivityIndicator()),
      ));
    });
    return NotificationListener<ScrollNotification>(
        onNotification: _onScroll,
        child: CupertinoScrollbar(child: CustomScrollView(
          slivers: [
            navigationBar,
            SyncControl(),
            subscriptionList,
            loadMoreIndicator,
          ],
        )),
      );
      onNotification: _onScroll,
      child: CupertinoScrollbar(
          child: CustomScrollView(
        slivers: [
          navigationBar,
          SyncControl(),
          subscriptionList,
          loadMoreIndicator,
        ],
      )),
    );
  }
  
}
\ No newline at end of file
}

M lib/pages/subscription_list_page.dart => lib/pages/subscription_list_page.dart +83 -71
@@ 13,7 13,7 @@ import 'package:fluent_reader_lite/utils/colors.dart';
import 'package:fluent_reader_lite/utils/global.dart';
import 'package:fluent_reader_lite/utils/store.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/material.dart' hide Badge;
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';


@@ 37,7 37,8 @@ class _SubscriptionListPageState extends State<SubscriptionListPage> {
  bool unreadOnly = Store.sp.getBool(StoreKeys.UNREAD_SUBS_ONLY) ?? false;

  void _onScrollTop() {
    if (widget.scrollTopNotifier.index == 1 && !Navigator.of(context).canPop()) {
    if (widget.scrollTopNotifier.index == 1 &&
        !Navigator.of(context).canPop()) {
      PrimaryScrollController.of(context).animateTo(
        0,
        curve: Curves.easeOut,


@@ 51,7 52,7 @@ class _SubscriptionListPageState extends State<SubscriptionListPage> {
    super.initState();
    widget.scrollTopNotifier.addListener(_onScrollTop);
  }
  

  @override
  void dispose() {
    widget.scrollTopNotifier.removeListener(_onScrollTop);


@@ 65,7 66,9 @@ class _SubscriptionListPageState extends State<SubscriptionListPage> {
        builder: (context) => GroupListPage(),
      ));
    } else {
      setState(() { transitioning = true; });
      setState(() {
        transitioning = true;
      });
      result = await CupertinoScaffold.showCupertinoModalBottomSheet(
        context: context,
        useRootNavigator: true,


@@ 93,13 96,16 @@ class _SubscriptionListPageState extends State<SubscriptionListPage> {
      }
    }
    await Future.delayed(Duration(milliseconds: 300));
    setState(() { transitioning = false; });
    setState(() {
      transitioning = false;
    });
  }

  void _openMarkAllModal() {
    showCupertinoModalPopup(
      context: context,
      builder: (context) => MarkAllActionSheet(sids == null ? {} : Set.from(sids)),
      builder: (context) =>
          MarkAllActionSheet(sids == null ? {} : Set.from(sids)),
    );
  }



@@ 116,7 122,9 @@ class _SubscriptionListPageState extends State<SubscriptionListPage> {

  void _toggleUnreadOnly() {
    HapticFeedback.mediumImpact();
    setState(() { unreadOnly = !unreadOnly; });
    setState(() {
      unreadOnly = !unreadOnly;
    });
    _onScrollTop();
    Store.sp.setBool(StoreKeys.UNREAD_SUBS_ONLY, unreadOnly);
  }


@@ 129,7 137,8 @@ class _SubscriptionListPageState extends State<SubscriptionListPage> {
  }

  Widget _buildUnreadTip() {
    return SliverToBoxAdapter(child: Container(
    return SliverToBoxAdapter(
        child: Container(
      padding: EdgeInsets.all(16),
      child: ClipRRect(
        borderRadius: BorderRadius.circular(16),


@@ 143,7 152,8 @@ class _SubscriptionListPageState extends State<SubscriptionListPage> {
                padding: EdgeInsets.only(right: 12),
                child: Icon(Icons.radio_button_checked),
              ),
              Flexible(child: Column(
              Flexible(
                  child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(


@@ 179,58 189,60 @@ class _SubscriptionListPageState extends State<SubscriptionListPage> {
          Container(
            constraints: BoxConstraints(
              maxWidth: Global.isTablet
                ? 260
                : MediaQuery.of(context).size.width - 60,
                  ? 260
                  : MediaQuery.of(context).size.width - 60,
            ),
            child: Text(
              title ?? S.of(context).subscriptions, 
              title ?? S.of(context).subscriptions,
              overflow: TextOverflow.ellipsis,
            ),
          ),
          if (unreadOnly) Padding(
            padding: EdgeInsets.only(left: 4),
            child: Icon(Icons.radio_button_checked, size: 18),
          ),
          if (unreadOnly)
            Padding(
              padding: EdgeInsets.only(left: 4),
              child: Icon(Icons.radio_button_checked, size: 18),
            ),
        ],
      ),
    );
    final navigationBar = CupertinoSliverNavigationBar(
      stretch: false,
      largeTitle: titleWidget,
      heroTag: "subscriptions",
      transitionBetweenRoutes: true,
      backgroundColor: transitioning ? MyColors.tileBackground : CupertinoColors.systemBackground,
      leading: CupertinoButton(
        minSize: 36,
        padding: EdgeInsets.zero,
        child: Text(S.of(context).groups),
        onPressed: _openGroups,
      ),
      trailing: Container(
        transform: Matrix4.translationValues(12, 0, 0),
        child: Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            CupertinoButton(
              padding: EdgeInsets.zero,
              child: Icon(
                CupertinoIcons.checkmark_circle,
                semanticLabel: S.of(context).markAll,
        stretch: false,
        largeTitle: titleWidget,
        heroTag: "subscriptions",
        transitionBetweenRoutes: true,
        backgroundColor: transitioning
            ? MyColors.tileBackground
            : CupertinoColors.systemBackground,
        leading: CupertinoButton(
          minSize: 36,
          padding: EdgeInsets.zero,
          child: Text(S.of(context).groups),
          onPressed: _openGroups,
        ),
        trailing: Container(
          transform: Matrix4.translationValues(12, 0, 0),
          child: Row(
            mainAxisSize: MainAxisSize.min,
            children: [
              CupertinoButton(
                padding: EdgeInsets.zero,
                child: Icon(
                  CupertinoIcons.checkmark_circle,
                  semanticLabel: S.of(context).markAll,
                ),
                onPressed: _openMarkAllModal,
              ),
              onPressed: _openMarkAllModal,
            ),
            CupertinoButton(
              padding: EdgeInsets.zero,
              child: Icon(
                CupertinoIcons.settings,
                semanticLabel: S.of(context).settings,
              CupertinoButton(
                padding: EdgeInsets.zero,
                child: Icon(
                  CupertinoIcons.settings,
                  semanticLabel: S.of(context).settings,
                ),
                onPressed: _openSettings,
              ),
              onPressed: _openSettings,
            ),
          ],
        ), 
      )
    );
            ],
          ),
        ));
    final sourcesList = Consumer<SourcesModel>(
      builder: (context, sourcesModel, child) {
        List<RSSSource> sources;


@@ 275,14 287,14 @@ class _SubscriptionListPageState extends State<SubscriptionListPage> {
                children: [
                  Text(
                    syncModel.lastSyncSuccess
                      ? S.of(context).lastSyncSuccess
                      : S.of(context).lastSyncFailure,
                        ? S.of(context).lastSyncSuccess
                        : S.of(context).lastSyncFailure,
                    style: syncStyle,
                  ),
                  Text(
                    DateFormat
                      .Md(Localizations.localeOf(context).toString())
                      .add_Hm().format(syncModel.lastSynced),
                    DateFormat.Md(Localizations.localeOf(context).toString())
                        .add_Hm()
                        .format(syncModel.lastSynced),
                    style: syncStyle,
                  ),
                ],


@@ 292,21 304,23 @@ class _SubscriptionListPageState extends State<SubscriptionListPage> {
        );
      },
    );
    return CupertinoScrollbar(child: CustomScrollView(
      slivers: [
        navigationBar,
        SyncControl(),
        if (Global.sourcesModel.showUnreadTip) _buildUnreadTip(),
        if (sids != null && sids.length > 0) Consumer<SourcesModel>(
    return CupertinoScrollbar(
        child: CustomScrollView(slivers: [
      navigationBar,
      SyncControl(),
      if (Global.sourcesModel.showUnreadTip) _buildUnreadTip(),
      if (sids != null && sids.length > 0)
        Consumer<SourcesModel>(
          builder: (context, sourcesModel, child) {
            var count = sids
              .map((sid) => sourcesModel.getSource(sid))
              .fold(0, (c, s) => c + s.unreadCount);
            return SliverToBoxAdapter(child: MyListTile(
                .map((sid) => sourcesModel.getSource(sid))
                .fold(0, (c, s) => c + s.unreadCount);
            return SliverToBoxAdapter(
                child: MyListTile(
              title: Text(S.of(context).allArticles),
              trailing: count > 0 ? Badge(count) : null,
              trailingChevron: false,
              onTap: () async { 
              onTap: () async {
                await Global.feedsModel.initSourcesFeed(sids.toList());
                Navigator.of(context).pushNamed("/feed", arguments: title);
              },


@@ 314,10 328,8 @@ class _SubscriptionListPageState extends State<SubscriptionListPage> {
            ));
          },
        ),
        sourcesList,
        syncInfo,
      ]
    ));
      sourcesList,
      syncInfo,
    ]));
  }
  
}
\ No newline at end of file
}

M pubspec.lock => pubspec.lock +264 -209
@@ 5,114 5,122 @@ packages:
    dependency: transitive
    description:
      name: async
      url: "https://pub.dartlang.org"
      sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0
      url: "https://pub.dev"
    source: hosted
    version: "2.8.2"
    version: "2.10.0"
  auth_header:
    dependency: transitive
    description:
      name: auth_header
      url: "https://pub.dartlang.org"
      sha256: "0a3938128b6124530de93ce1a20ccb58639195fe7952f638248ea1bc0e5408eb"
      url: "https://pub.dev"
    source: hosted
    version: "3.0.1"
  boolean_selector:
    dependency: transitive
    description:
      name: boolean_selector
      url: "https://pub.dartlang.org"
      sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
      url: "https://pub.dev"
    source: hosted
    version: "2.1.0"
    version: "2.1.1"
  cached_network_image:
    dependency: "direct main"
    description:
      name: cached_network_image
      url: "https://pub.dartlang.org"
      sha256: fd3d0dc1d451f9a252b32d95d3f0c3c487bc41a75eba2e6097cb0b9c71491b15
      url: "https://pub.dev"
    source: hosted
    version: "3.2.1"
    version: "3.2.3"
  cached_network_image_platform_interface:
    dependency: transitive
    description:
      name: cached_network_image_platform_interface
      url: "https://pub.dartlang.org"
      sha256: bb2b8403b4ccdc60ef5f25c70dead1f3d32d24b9d6117cfc087f496b178594a7
      url: "https://pub.dev"
    source: hosted
    version: "1.0.0"
    version: "2.0.0"
  cached_network_image_web:
    dependency: transitive
    description:
      name: cached_network_image_web
      url: "https://pub.dartlang.org"
      sha256: b8eb814ebfcb4dea049680f8c1ffb2df399e4d03bf7a352c775e26fa06e02fa0
      url: "https://pub.dev"
    source: hosted
    version: "1.0.1"
    version: "1.0.2"
  characters:
    dependency: transitive
    description:
      name: characters
      url: "https://pub.dartlang.org"
    source: hosted
    version: "1.2.0"
  charcode:
    dependency: transitive
    description:
      name: charcode
      url: "https://pub.dartlang.org"
      sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c
      url: "https://pub.dev"
    source: hosted
    version: "1.3.1"
    version: "1.2.1"
  clock:
    dependency: transitive
    description:
      name: clock
      url: "https://pub.dartlang.org"
      sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
      url: "https://pub.dev"
    source: hosted
    version: "1.1.0"
    version: "1.1.1"
  collection:
    dependency: transitive
    description:
      name: collection
      url: "https://pub.dartlang.org"
      sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0
      url: "https://pub.dev"
    source: hosted
    version: "1.16.0"
    version: "1.17.0"
  crypto:
    dependency: "direct main"
    description:
      name: crypto
      url: "https://pub.dartlang.org"
      sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
      url: "https://pub.dev"
    source: hosted
    version: "3.0.2"
    version: "3.0.3"
  csslib:
    dependency: transitive
    description:
      name: csslib
      url: "https://pub.dartlang.org"
      sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb"
      url: "https://pub.dev"
    source: hosted
    version: "0.17.2"
    version: "1.0.0"
  cupertino_icons:
    dependency: "direct main"
    description:
      name: cupertino_icons
      url: "https://pub.dartlang.org"
      sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
      url: "https://pub.dev"
    source: hosted
    version: "1.0.5"
    version: "1.0.6"
  fake_async:
    dependency: transitive
    description:
      name: fake_async
      url: "https://pub.dartlang.org"
      sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
      url: "https://pub.dev"
    source: hosted
    version: "1.3.0"
    version: "1.3.1"
  ffi:
    dependency: transitive
    description:
      name: ffi
      url: "https://pub.dartlang.org"
      sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99
      url: "https://pub.dev"
    source: hosted
    version: "2.0.1"
    version: "2.0.2"
  file:
    dependency: transitive
    description:
      name: file
      url: "https://pub.dartlang.org"
      sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
      url: "https://pub.dev"
    source: hosted
    version: "6.1.2"
    version: "6.1.4"
  flutter:
    dependency: "direct main"
    description: flutter


@@ 122,16 130,18 @@ packages:
    dependency: transitive
    description:
      name: flutter_blurhash
      url: "https://pub.dartlang.org"
      sha256: "05001537bd3fac7644fa6558b09ec8c0a3f2eba78c0765f88912882b1331a5c6"
      url: "https://pub.dev"
    source: hosted
    version: "0.7.0"
  flutter_cache_manager:
    dependency: "direct main"
    description:
      name: flutter_cache_manager
      url: "https://pub.dartlang.org"
      sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba"
      url: "https://pub.dev"
    source: hosted
    version: "3.3.0"
    version: "3.3.1"
  flutter_localizations:
    dependency: "direct main"
    description: flutter


@@ 151,324 161,330 @@ packages:
    dependency: "direct main"
    description:
      name: html
      url: "https://pub.dartlang.org"
      sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a"
      url: "https://pub.dev"
    source: hosted
    version: "0.15.0"
    version: "0.15.4"
  http:
    dependency: "direct main"
    description:
      name: http
      url: "https://pub.dartlang.org"
      sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2"
      url: "https://pub.dev"
    source: hosted
    version: "0.13.4"
    version: "0.13.6"
  http_parser:
    dependency: transitive
    description:
      name: http_parser
      url: "https://pub.dartlang.org"
      sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
      url: "https://pub.dev"
    source: hosted
    version: "4.0.1"
    version: "4.0.2"
  http_server:
    dependency: transitive
    description:
      name: http_server
      url: "https://pub.dartlang.org"
      sha256: f1fd4de4f57ba5597fddf8029bc0d161e9151a69e1d87ccddec901d2b5a45b10
      url: "https://pub.dev"
    source: hosted
    version: "1.0.0"
  intl:
    dependency: "direct main"
    description:
      name: intl
      url: "https://pub.dartlang.org"
      sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91"
      url: "https://pub.dev"
    source: hosted
    version: "0.17.0"
  jaguar:
    dependency: "direct main"
    description:
      name: jaguar
      url: "https://pub.dartlang.org"
      sha256: "1614ea947a81f2160fd6f962c5bff0b3f11eb6e5417d47140d447f4758a7f164"
      url: "https://pub.dev"
    source: hosted
    version: "3.1.3"
  jaguar_common:
    dependency: transitive
    description:
      name: jaguar_common
      url: "https://pub.dartlang.org"
      sha256: "2d7f08e6370edbc0a2433484aa8ae66ce29885747bb591e9d322e687487d731a"
      url: "https://pub.dev"
    source: hosted
    version: "3.0.0"
  jaguar_flutter_asset:
    dependency: "direct main"
    description:
      name: jaguar_flutter_asset
      url: "https://pub.dartlang.org"
      sha256: a2ba50f9d4efda8081e78d80cd0fe660fd2f43ed60e30e08d6ae2ab47e4553c5
      url: "https://pub.dev"
    source: hosted
    version: "3.0.0"
  js:
    dependency: transitive
    description:
      name: js
      url: "https://pub.dartlang.org"
      sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7"
      url: "https://pub.dev"
    source: hosted
    version: "0.6.4"
    version: "0.6.5"
  logging:
    dependency: transitive
    description:
      name: logging
      url: "https://pub.dartlang.org"
      sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
      url: "https://pub.dev"
    source: hosted
    version: "1.0.2"
    version: "1.2.0"
  lpinyin:
    dependency: "direct main"
    description:
      name: lpinyin
      url: "https://pub.dartlang.org"
      sha256: "0bb843363f1f65170efd09fbdfc760c7ec34fc6354f9fcb2f89e74866a0d814a"
      url: "https://pub.dev"
    source: hosted
    version: "2.0.3"
  matcher:
    dependency: transitive
    description:
      name: matcher
      url: "https://pub.dartlang.org"
      sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72"
      url: "https://pub.dev"
    source: hosted
    version: "0.12.11"
    version: "0.12.13"
  material_color_utilities:
    dependency: transitive
    description:
      name: material_color_utilities
      url: "https://pub.dartlang.org"
      sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
      url: "https://pub.dev"
    source: hosted
    version: "0.1.4"
    version: "0.2.0"
  meta:
    dependency: transitive
    description:
      name: meta
      url: "https://pub.dartlang.org"
      sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42"
      url: "https://pub.dev"
    source: hosted
    version: "1.7.0"
    version: "1.8.0"
  mime:
    dependency: transitive
    description:
      name: mime
      url: "https://pub.dartlang.org"
      sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e
      url: "https://pub.dev"
    source: hosted
    version: "1.0.2"
    version: "1.0.4"
  modal_bottom_sheet:
    dependency: "direct main"
    description:
      name: modal_bottom_sheet
      url: "https://pub.dartlang.org"
      sha256: "3bba63c62d35c931bce7f8ae23a47f9a05836d8cb3c11122ada64e0b2f3d718f"
      url: "https://pub.dev"
    source: hosted
    version: "2.1.0"
    version: "3.0.0-pre"
  nested:
    dependency: transitive
    description:
      name: nested
      url: "https://pub.dartlang.org"
      sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
      url: "https://pub.dev"
    source: hosted
    version: "1.0.0"
  octo_image:
    dependency: transitive
    description:
      name: octo_image
      url: "https://pub.dartlang.org"
      sha256: "107f3ed1330006a3bea63615e81cf637433f5135a52466c7caa0e7152bca9143"
      url: "https://pub.dev"
    source: hosted
    version: "1.0.2"
  overlay_dialog:
    dependency: "direct main"
    description:
      name: overlay_dialog
      url: "https://pub.dartlang.org"
      sha256: eda742cb93a7c8f34bc45b6b73fc586018a8b3f970b421a1df6656b5f311858f
      url: "https://pub.dev"
    source: hosted
    version: "0.2.1"
    version: "0.2.2"
  package_info:
    dependency: "direct main"
    description:
      name: package_info
      url: "https://pub.dartlang.org"
      sha256: "6c07d9d82c69e16afeeeeb6866fe43985a20b3b50df243091bfc4a4ad2b03b75"
      url: "https://pub.dev"
    source: hosted
    version: "2.0.2"
  path:
    dependency: "direct main"
    description:
      name: path
      url: "https://pub.dartlang.org"
      sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b
      url: "https://pub.dev"
    source: hosted
    version: "1.8.1"
    version: "1.8.2"
  path_provider:
    dependency: transitive
    description:
      name: path_provider
      url: "https://pub.dartlang.org"
      sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
      url: "https://pub.dev"
    source: hosted
    version: "2.0.11"
    version: "2.1.1"
  path_provider_android:
    dependency: transitive
    description:
      name: path_provider_android
      url: "https://pub.dartlang.org"
      sha256: "6b8b19bd80da4f11ce91b2d1fb931f3006911477cec227cce23d3253d80df3f1"
      url: "https://pub.dev"
    source: hosted
    version: "2.0.15"
  path_provider_ios:
    version: "2.2.0"
  path_provider_foundation:
    dependency: transitive
    description:
      name: path_provider_ios
      url: "https://pub.dartlang.org"
      name: path_provider_foundation
      sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
      url: "https://pub.dev"
    source: hosted
    version: "2.0.10"
    version: "2.3.1"
  path_provider_linux:
    dependency: transitive
    description:
      name: path_provider_linux
      url: "https://pub.dartlang.org"
    source: hosted
    version: "2.1.7"
  path_provider_macos:
    dependency: transitive
    description:
      name: path_provider_macos
      url: "https://pub.dartlang.org"
      sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
      url: "https://pub.dev"
    source: hosted
    version: "2.0.6"
    version: "2.2.1"
  path_provider_platform_interface:
    dependency: transitive
    description:
      name: path_provider_platform_interface
      url: "https://pub.dartlang.org"
      sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
      url: "https://pub.dev"
    source: hosted
    version: "2.0.4"
    version: "2.1.1"
  path_provider_windows:
    dependency: transitive
    description:
      name: path_provider_windows
      url: "https://pub.dartlang.org"
      sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
      url: "https://pub.dev"
    source: hosted
    version: "2.1.0"
    version: "2.2.1"
  path_tree:
    dependency: transitive
    description:
      name: path_tree
      url: "https://pub.dartlang.org"
      sha256: "0f8152eba14c197237cc03445d75ba33a048f0cd15030df288cbe02f93f2ece3"
      url: "https://pub.dev"
    source: hosted
    version: "3.0.0"
  pedantic:
    dependency: transitive
    description:
      name: pedantic
      url: "https://pub.dartlang.org"
    source: hosted
    version: "1.11.1"
  platform:
    dependency: transitive
    description:
      name: platform
      url: "https://pub.dartlang.org"
      sha256: ae68c7bfcd7383af3629daafb32fb4e8681c7154428da4febcff06200585f102
      url: "https://pub.dev"
    source: hosted
    version: "3.1.0"
    version: "3.1.2"
  plugin_platform_interface:
    dependency: transitive
    description:
      name: plugin_platform_interface
      url: "https://pub.dartlang.org"
    source: hosted
    version: "2.1.2"
  process:
    dependency: transitive
    description:
      name: process
      url: "https://pub.dartlang.org"
      sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d
      url: "https://pub.dev"
    source: hosted
    version: "4.2.4"
    version: "2.1.6"
  provider:
    dependency: "direct main"
    description:
      name: provider
      url: "https://pub.dartlang.org"
      sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f
      url: "https://pub.dev"
    source: hosted
    version: "6.0.3"
  quiver:
    dependency: transitive
    description:
      name: quiver
      url: "https://pub.dartlang.org"
    source: hosted
    version: "3.1.0"
    version: "6.0.5"
  responsive_builder:
    dependency: "direct main"
    description:
      name: responsive_builder
      url: "https://pub.dartlang.org"
      sha256: f01bc341c73b6db7bd6319e22d2c160f28f924399ae46e6699ecc8160ba2765c
      url: "https://pub.dev"
    source: hosted
    version: "0.4.2"
    version: "0.4.3"
  rxdart:
    dependency: transitive
    description:
      name: rxdart
      url: "https://pub.dartlang.org"
      sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb"
      url: "https://pub.dev"
    source: hosted
    version: "0.27.4"
    version: "0.27.7"
  share:
    dependency: "direct main"
    description:
      name: share
      url: "https://pub.dartlang.org"
      sha256: "97e6403f564ed1051a01534c2fc919cb6e40ea55e60a18ec23cee6e0ce19f4be"
      url: "https://pub.dev"
    source: hosted
    version: "2.0.4"
  shared_preferences:
    dependency: "direct main"
    description:
      name: shared_preferences
      url: "https://pub.dartlang.org"
      sha256: b7f41bad7e521d205998772545de63ff4e6c97714775902c199353f8bf1511ac
      url: "https://pub.dev"
    source: hosted
    version: "2.0.15"
    version: "2.2.1"
  shared_preferences_android:
    dependency: transitive
    description:
      name: shared_preferences_android
      url: "https://pub.dartlang.org"
      sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06"
      url: "https://pub.dev"
    source: hosted
    version: "2.0.12"
  shared_preferences_ios:
    version: "2.2.1"
  shared_preferences_foundation:
    dependency: transitive
    description:
      name: shared_preferences_ios
      url: "https://pub.dartlang.org"
      name: shared_preferences_foundation
      sha256: "7bf53a9f2d007329ee6f3df7268fd498f8373602f943c975598bbb34649b62a7"
      url: "https://pub.dev"
    source: hosted
    version: "2.1.1"
    version: "2.3.4"
  shared_preferences_linux:
    dependency: transitive
    description:
      name: shared_preferences_linux
      url: "https://pub.dartlang.org"
    source: hosted
    version: "2.1.1"
  shared_preferences_macos:
    dependency: transitive
    description:
      name: shared_preferences_macos
      url: "https://pub.dartlang.org"
      sha256: c2eb5bf57a2fe9ad6988121609e47d3e07bb3bdca5b6f8444e4cf302428a128a
      url: "https://pub.dev"
    source: hosted
    version: "2.0.4"
    version: "2.3.1"
  shared_preferences_platform_interface:
    dependency: transitive
    description:
      name: shared_preferences_platform_interface
      url: "https://pub.dartlang.org"
      sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a
      url: "https://pub.dev"
    source: hosted
    version: "2.0.0"
    version: "2.3.1"
  shared_preferences_web:
    dependency: transitive
    description:
      name: shared_preferences_web
      url: "https://pub.dartlang.org"
      sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf
      url: "https://pub.dev"
    source: hosted
    version: "2.0.4"
    version: "2.2.1"
  shared_preferences_windows:
    dependency: transitive
    description:
      name: shared_preferences_windows
      url: "https://pub.dartlang.org"
      sha256: f763a101313bd3be87edffe0560037500967de9c394a714cd598d945517f694f
      url: "https://pub.dev"
    source: hosted
    version: "2.1.1"
    version: "2.3.1"
  sky_engine:
    dependency: transitive
    description: flutter


@@ 478,219 494,258 @@ packages:
    dependency: transitive
    description:
      name: source_span
      url: "https://pub.dartlang.org"
      sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
      url: "https://pub.dev"
    source: hosted
    version: "1.8.2"
    version: "1.9.1"
  sprintf:
    dependency: transitive
    description:
      name: sprintf
      sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
      url: "https://pub.dev"
    source: hosted
    version: "7.0.0"
  sqflite:
    dependency: "direct main"
    description:
      name: sqflite
      url: "https://pub.dartlang.org"
      sha256: b4d6710e1200e96845747e37338ea8a819a12b51689a3bcf31eff0003b37a0b9
      url: "https://pub.dev"
    source: hosted
    version: "2.0.2+1"
    version: "2.2.8+4"
  sqflite_common:
    dependency: transitive
    description:
      name: sqflite_common
      url: "https://pub.dartlang.org"
      sha256: "8f7603f3f8f126740bc55c4ca2d1027aab4b74a1267a3e31ce51fe40e3b65b8f"
      url: "https://pub.dev"
    source: hosted
    version: "2.2.1+1"
    version: "2.4.5+1"
  stack_trace:
    dependency: transitive
    description:
      name: stack_trace
      url: "https://pub.dartlang.org"
      sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
      url: "https://pub.dev"
    source: hosted
    version: "1.10.0"
    version: "1.11.0"
  stream_channel:
    dependency: transitive
    description:
      name: stream_channel
      url: "https://pub.dartlang.org"
      sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
      url: "https://pub.dev"
    source: hosted
    version: "2.1.0"
    version: "2.1.1"
  string_scanner:
    dependency: transitive
    description:
      name: string_scanner
      url: "https://pub.dartlang.org"
      sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
      url: "https://pub.dev"
    source: hosted
    version: "1.1.0"
    version: "1.2.0"
  synchronized:
    dependency: transitive
    description:
      name: synchronized
      url: "https://pub.dartlang.org"
      sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60"
      url: "https://pub.dev"
    source: hosted
    version: "3.0.0+2"
    version: "3.1.0"
  term_glyph:
    dependency: transitive
    description:
      name: term_glyph
      url: "https://pub.dartlang.org"
      sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
      url: "https://pub.dev"
    source: hosted
    version: "1.2.0"
    version: "1.2.1"
  test_api:
    dependency: transitive
    description:
      name: test_api
      url: "https://pub.dartlang.org"
      sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206
      url: "https://pub.dev"
    source: hosted
    version: "0.4.9"
    version: "0.4.16"
  tuple:
    dependency: "direct main"
    description:
      name: tuple
      url: "https://pub.dartlang.org"
      sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
      url: "https://pub.dev"
    source: hosted
    version: "2.0.0"
    version: "2.0.2"
  typed_data:
    dependency: transitive
    description:
      name: typed_data
      url: "https://pub.dartlang.org"
      sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
      url: "https://pub.dev"
    source: hosted
    version: "1.3.1"
    version: "1.3.2"
  uni_links:
    dependency: "direct main"
    description:
      name: uni_links
      url: "https://pub.dartlang.org"
      sha256: "051098acfc9e26a9fde03b487bef5d3d228ca8f67693480c6f33fd4fbb8e2b6e"
      url: "https://pub.dev"
    source: hosted
    version: "0.5.1"
  uni_links_platform_interface:
    dependency: transitive
    description:
      name: uni_links_platform_interface
      url: "https://pub.dartlang.org"
      sha256: "929cf1a71b59e3b7c2d8a2605a9cf7e0b125b13bc858e55083d88c62722d4507"
      url: "https://pub.dev"
    source: hosted
    version: "1.0.0"
  uni_links_web:
    dependency: transitive
    description:
      name: uni_links_web
      url: "https://pub.dartlang.org"
      sha256: "7539db908e25f67de2438e33cc1020b30ab94e66720b5677ba6763b25f6394df"
      url: "https://pub.dev"
    source: hosted
    version: "0.1.0"
  universal_io:
    dependency: transitive
    description:
      name: universal_io
      url: "https://pub.dartlang.org"
      sha256: "06866290206d196064fd61df4c7aea1ffe9a4e7c4ccaa8fcded42dd41948005d"
      url: "https://pub.dev"
    source: hosted
    version: "2.0.4"
    version: "2.2.0"
  url_launcher:
    dependency: "direct main"
    description:
      name: url_launcher
      url: "https://pub.dartlang.org"
      sha256: eb1e00ab44303d50dd487aab67ebc575456c146c6af44422f9c13889984c00f3
      url: "https://pub.dev"
    source: hosted
    version: "6.1.4"
    version: "6.1.11"
  url_launcher_android:
    dependency: transitive
    description:
      name: url_launcher_android
      url: "https://pub.dartlang.org"
      sha256: b04af59516ab45762b2ca6da40fa830d72d0f6045cd97744450b73493fa76330
      url: "https://pub.dev"
    source: hosted
    version: "6.0.17"
    version: "6.1.0"
  url_launcher_ios:
    dependency: transitive
    description:
      name: url_launcher_ios
      url: "https://pub.dartlang.org"
      sha256: "7c65021d5dee51813d652357bc65b8dd4a6177082a9966bc8ba6ee477baa795f"
      url: "https://pub.dev"
    source: hosted
    version: "6.0.17"
    version: "6.1.5"
  url_launcher_linux:
    dependency: transitive
    description:
      name: url_launcher_linux
      url: "https://pub.dartlang.org"
      sha256: b651aad005e0cb06a01dbd84b428a301916dc75f0e7ea6165f80057fee2d8e8e
      url: "https://pub.dev"
    source: hosted
    version: "3.0.1"
    version: "3.0.6"
  url_launcher_macos:
    dependency: transitive
    description:
      name: url_launcher_macos
      url: "https://pub.dartlang.org"
      sha256: b55486791f666e62e0e8ff825e58a023fd6b1f71c49926483f1128d3bbd8fe88
      url: "https://pub.dev"
    source: hosted
    version: "3.0.1"
    version: "3.0.7"
  url_launcher_platform_interface:
    dependency: transitive
    description:
      name: url_launcher_platform_interface
      url: "https://pub.dartlang.org"
      sha256: "95465b39f83bfe95fcb9d174829d6476216f2d548b79c38ab2506e0458787618"
      url: "https://pub.dev"
    source: hosted
    version: "2.1.0"
    version: "2.1.5"
  url_launcher_web:
    dependency: transitive
    description:
      name: url_launcher_web
      url: "https://pub.dartlang.org"
      sha256: ba140138558fcc3eead51a1c42e92a9fb074a1b1149ed3c73e66035b2ccd94f2
      url: "https://pub.dev"
    source: hosted
    version: "2.0.12"
    version: "2.0.19"
  url_launcher_windows:
    dependency: transitive
    description:
      name: url_launcher_windows
      url: "https://pub.dartlang.org"
      sha256: "95fef3129dc7cfaba2bc3d5ba2e16063bb561fc6d78e63eee16162bc70029069"
      url: "https://pub.dev"
    source: hosted
    version: "3.0.1"
    version: "3.0.8"
  uuid:
    dependency: transitive
    description:
      name: uuid
      url: "https://pub.dartlang.org"
      sha256: e03928880bdbcbf496fb415573f5ab7b1ea99b9b04f669c01104d085893c3134
      url: "https://pub.dev"
    source: hosted
    version: "3.0.6"
    version: "4.0.0"
  vector_math:
    dependency: transitive
    description:
      name: vector_math
      url: "https://pub.dartlang.org"
      sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
      url: "https://pub.dev"
    source: hosted
    version: "2.1.2"
    version: "2.1.4"
  webview_flutter:
    dependency: "direct main"
    description:
      name: webview_flutter
      url: "https://pub.dartlang.org"
      sha256: "392c1d83b70fe2495de3ea2c84531268d5b8de2de3f01086a53334d8b6030a88"
      url: "https://pub.dev"
    source: hosted
    version: "3.0.4"
  webview_flutter_android:
    dependency: transitive
    description:
      name: webview_flutter_android
      url: "https://pub.dartlang.org"
      sha256: "8b3b2450e98876c70bfcead876d9390573b34b9418c19e28168b74f6cb252dbd"
      url: "https://pub.dev"
    source: hosted
    version: "2.8.14"
    version: "2.10.4"
  webview_flutter_platform_interface:
    dependency: transitive
    description:
      name: webview_flutter_platform_interface
      url: "https://pub.dartlang.org"
      sha256: "812165e4e34ca677bdfbfa58c01e33b27fd03ab5fa75b70832d4b7d4ca1fa8cf"
      url: "https://pub.dev"
    source: hosted
    version: "1.9.1"
    version: "1.9.5"
  webview_flutter_wkwebview:
    dependency: transitive
    description:
      name: webview_flutter_wkwebview
      url: "https://pub.dartlang.org"
      sha256: a5364369c758892aa487cbf59ea41d9edd10f9d9baf06a94e80f1bd1b4c7bbc0
      url: "https://pub.dev"
    source: hosted
    version: "2.8.1"
    version: "2.9.5"
  win32:
    dependency: transitive
    description:
      name: win32
      url: "https://pub.dartlang.org"
      sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c"
      url: "https://pub.dev"
    source: hosted
    version: "2.7.0"
    version: "4.1.4"
  xdg_directories:
    dependency: transitive
    description:
      name: xdg_directories
      url: "https://pub.dartlang.org"
      sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2"
      url: "https://pub.dev"
    source: hosted
    version: "0.2.0+1"
    version: "1.0.3"
sdks:
  dart: ">=2.17.0 <3.0.0"
  flutter: ">=3.0.0"
  dart: ">=2.19.0 <3.0.0"
  flutter: ">=3.7.0"

M pubspec.yaml => pubspec.yaml +2 -2
@@ 15,7 15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.0.3+10
version: 1.0.4+11

environment:
  sdk: ">=2.7.0 <3.0.0"


@@ 45,7 45,7 @@ dependencies:
  flutter_cache_manager: ^3.3.0
  lpinyin: ^2.0.3
  uni_links: ^0.5.1
  modal_bottom_sheet: ^2.1.0
  modal_bottom_sheet: ^3.0.0-pre
  overlay_dialog: ^0.2.0