~cytrogen/fluent-reader-mobile

d61062f4139b621c3e58f6c69f815e46ba83ec65 — Bruce Liu 5 years ago c0d14ef
add unread sources only option
M assets/article/article.html => assets/article/article.html +1 -0
@@ 3,6 3,7 @@
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="referrer" content="no-referrer">
    <meta http-equiv="Content-Security-Policy"
        content="default-src 'none'; script-src 'self'; img-src http: https: data:; style-src 'self' 'unsafe-inline'; frame-src http: https:; media-src http: https:; connect-src https: http:">
    <title>Article</title>

M lib/l10n/intl_en.arb => lib/l10n/intl_en.arb +2 -1
@@ 87,5 87,6 @@
    "wentWrong": "Something went wrong.",
    "retry": "Retry",
    "copy": "Copy",
    "errorLog": "Error log"
    "errorLog": "Error log",
    "unreadSourceTip": "You can long press on the title of this page to toggle between all and unread subscriptions."
  }
\ No newline at end of file

M lib/l10n/intl_zh.arb => lib/l10n/intl_zh.arb +2 -1
@@ 87,5 87,6 @@
    "wentWrong": "发生错误",
    "retry": "重试",
    "copy": "复制",
    "errorLog": "错误日志"
    "errorLog": "错误日志",
    "unreadSourceTip": "您可以长按此页面的标题来切换全部订阅源或仅未读订阅源。"
  }
\ No newline at end of file

M lib/models/sources_model.dart => lib/models/sources_model.dart +12 -0
@@ 1,5 1,8 @@
import 'dart:collection';

import 'package:fluent_reader_lite/models/source.dart';
import 'package:fluent_reader_lite/utils/global.dart';
import 'package:fluent_reader_lite/utils/store.dart';
import 'package:fluent_reader_lite/utils/utils.dart';
import 'package:flutter/material.dart';
import 'package:html/parser.dart';


@@ 11,6 14,15 @@ import 'item.dart';
class SourcesModel with ChangeNotifier {
  Map<String, RSSSource> _sources = Map();
  Map<String, RSSSource> _deleted = Map();
  bool _showUnreadTip = Store.sp.getBool(StoreKeys.UNREAD_SOURCE_TIP) ?? true;

  bool get showUnreadTip => _showUnreadTip;
  set showUnreadTip(bool value) {
    if (_showUnreadTip != value) {
      _showUnreadTip = value;
      Store.sp.setBool(StoreKeys.UNREAD_SOURCE_TIP, value);
    }
  }

  bool has(String id) => _sources.containsKey(id);


M lib/pages/subscription_list_page.dart => lib/pages/subscription_list_page.dart +88 -2
@@ 33,6 33,7 @@ class _SubscriptionListPageState extends State<SubscriptionListPage> {
  List<String> sids;
  String title;
  bool transitioning = false;
  bool unreadOnly = false;

  void _onScrollTop() {
    if (widget.scrollTopNotifier.index == 1 && !Navigator.of(context).canPop()) {


@@ 106,15 107,93 @@ class _SubscriptionListPageState extends State<SubscriptionListPage> {
    }
  }

  void _toggleUnreadOnly() {
    HapticFeedback.mediumImpact();
    setState(() { unreadOnly = !unreadOnly; });
    _onScrollTop();
  }

  void _dismissTip() {
    if (Global.sourcesModel.showUnreadTip) {
      Global.sourcesModel.showUnreadTip = false;
      setState(() {});
    }
  }

  Widget _buildUnreadTip() {
    return SliverToBoxAdapter(child: Container(
      padding: EdgeInsets.all(16),
      child: ClipRRect(
        borderRadius: BorderRadius.circular(16),
        child: Container(
          padding: EdgeInsets.all(12),
          color: CupertinoColors.secondarySystemBackground.resolveFrom(context),
          child: Row(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Padding(
                padding: EdgeInsets.only(right: 12),
                child: Icon(Icons.radio_button_checked),
              ),
              Flexible(child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    S.of(context).unreadSourceTip,
                    style: TextStyle(
                      color: CupertinoColors.label.resolveFrom(context),
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  Padding(padding: EdgeInsets.only(bottom: 6)),
                  CupertinoButton(
                    minSize: 28,
                    padding: EdgeInsets.zero,
                    child: Text(S.of(context).confirm),
                    onPressed: _dismissTip,
                  ),
                ],
              )),
            ],
          ),
        ),
      ),
    ));
  }

  @override
  Widget build(BuildContext context) {
    final titleWidget = GestureDetector(
      onLongPress: _toggleUnreadOnly,
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          Container(
            constraints: BoxConstraints(
              maxWidth: Global.isTablet
                ? 260
                : MediaQuery.of(context).size.width - 60,
            ),
            child: Text(
              title ?? S.of(context).subscriptions, 
              overflow: TextOverflow.ellipsis,
            ),
          ),
          if (unreadOnly) Padding(
            padding: EdgeInsets.only(left: 4),
            child: Icon(Icons.radio_button_checked, size: 18),
          ),
        ],
      ),
    );
    final navigationBar = CupertinoSliverNavigationBar(
      stretch: false,
      largeTitle: Text(title ?? S.of(context).subscriptions),
      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,


@@ 149,10 228,16 @@ class _SubscriptionListPageState extends State<SubscriptionListPage> {
        List<RSSSource> sources;
        if (sids == null) {
          sources = Global.sourcesModel.getSources().toList();
          if (unreadOnly) {
            sources = sources.where((s) => s.unreadCount > 0).toList();
          }
        } else {
          sources = [];
          for (var sid in sids) {
            sources.add(Global.sourcesModel.getSource(sid));
            final source = Global.sourcesModel.getSource(sid);
            if (!unreadOnly || source.unreadCount > 0) {
              sources.add(source);
            }
          }
        }
        // Latest sources first


@@ 203,6 288,7 @@ class _SubscriptionListPageState extends State<SubscriptionListPage> {
      slivers: [
        navigationBar,
        SyncControl(),
        if (Global.sourcesModel.showUnreadTip) _buildUnreadTip(),
        if (sids != null) Consumer<SourcesModel>(
          builder: (context, sourcesModel, child) {
            var count = sids

M lib/utils/store.dart => lib/utils/store.dart +1 -0
@@ 24,6 24,7 @@ abstract class StoreKeys {
  static const DIM_READ = "dimRead";
  static const FEED_SWIPE_R = "feedSwipeR";
  static const FEED_SWIPE_L = "feedSwipeL";
  static const UNREAD_SOURCE_TIP = "unreadSourceTip";

  // Reading preferences
  static const ARTICLE_FONT_SIZE = "articleFontSize";

M pubspec.lock => pubspec.lock +7 -0
@@ 238,6 238,13 @@ packages:
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "0.11.4"
  lpinyin:
    dependency: "direct main"
    description:
      name: lpinyin
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.1.0"
  matcher:
    dependency: transitive
    description:

M pubspec.yaml => pubspec.yaml +2 -1
@@ 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.0+4
version: 1.0.1+5

environment:
  sdk: ">=2.7.0 <3.0.0"


@@ 43,6 43,7 @@ dependencies:
  responsive_builder: ^0.3.0
  cached_network_image: ^2.5.0
  flutter_cache_manager: ^2.1.0
  lpinyin: ^1.1.0
  modal_bottom_sheet: ^1.0.0+1
  overlay_dialog: ^0.0.3