~cytrogen/fluent-reader-mobile

b62144093d5def827aeb47e62253c11959615982 — 刘浩远 5 years ago f746c4b
add customizable text scale
M lib/l10n/intl_en.arb => lib/l10n/intl_en.arb +2 -1
@@ 61,7 61,8 @@
    "clearCache": "Clear cache",
    "autoDelete": "Auto delete items",
    "sync": "Sync",
    "onStart": "On start",
    "syncOnStart": "Sync on start",
    "inAppBrowser": "In-app browser",
    "lastSyncSuccess": "Last sync successful at",
    "lastSyncFailure": "Last sync failed at",
    "welcome": "Welcome",

M lib/l10n/intl_zh.arb => lib/l10n/intl_zh.arb +2 -1
@@ 61,7 61,8 @@
    "clearCache": "清理缓存",
    "autoDelete": "自动删除文章",
    "sync": "同步",
    "onStart": "打开应用时",
    "syncOnStart": "打开应用时同步",
    "inAppBrowser": "应用内浏览器",
    "lastSyncSuccess": "最后一次同步成功于",
    "lastSyncFailure": "最后一次同步失败于",
    "welcome": "欢迎",

M lib/main.dart => lib/main.dart +12 -3
@@ 19,7 19,6 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
import 'package:path/path.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:webview_flutter/webview_flutter.dart';


@@ 39,9 38,11 @@ void main() async {
  runApp(MyApp());
  SystemChannels.lifecycle.setMessageHandler((msg) {
    if (msg == AppLifecycleState.resumed.toString()) {
      if (Global.server != null) Global.server.restart();
      if (Global.globalModel.syncOnStart
        && DateTime.now().difference(Global.syncModel.lastSynced).inMinutes >= 10)
      Global.syncModel.syncWithService();
        && DateTime.now().difference(Global.syncModel.lastSynced).inMinutes >= 10) {
        Global.syncModel.syncWithService();
      }
    }
    return null;
  });


@@ 119,6 120,14 @@ class MyApp extends StatelessWidget {
            "/": (context) => CupertinoScaffold(body: HomePage()),
            ...baseRoutes,
          },
          builder: (context, child) {
            final mediaQueryData = MediaQuery.of(context);
            if (Global.globalModel.textScale == null) return child;
            return MediaQuery(
              data: mediaQueryData.copyWith(textScaleFactor: Global.globalModel.textScale),
              child: child
            );
          },
        ),
      ),
    );

M lib/models/global_model.dart => lib/models/global_model.dart +23 -0
@@ 1,3 1,5 @@
import 'dart:io';

import 'package:fluent_reader_lite/utils/store.dart';
import 'package:flutter/material.dart';



@@ 10,6 12,8 @@ class GlobalModel with ChangeNotifier {
  Locale _locale = Store.getLocale();
  int _keepItemsDays = Store.sp.getInt(StoreKeys.KEEP_ITEMS_DAYS) ?? 21;
  bool _syncOnStart = Store.sp.getBool(StoreKeys.SYNC_ON_START) ?? true;
  bool _inAppBrowser = Store.sp.getBool(StoreKeys.IN_APP_BROWSER) ?? Platform.isIOS;
  double _textScale = Store.sp.getDouble(StoreKeys.TEXT_SCALE);

  ThemeSetting get theme => _theme;
  set theme(ThemeSetting value) {


@@ 44,4 48,23 @@ class GlobalModel with ChangeNotifier {
    _syncOnStart = value;
    Store.sp.setBool(StoreKeys.SYNC_ON_START, value);
  }

  bool get inAppBrowser => _inAppBrowser;
  set inAppBrowser(bool value) {
    _inAppBrowser = value;
    Store.sp.setBool(StoreKeys.IN_APP_BROWSER, value);
  }

  double get textScale => _textScale;
  set textScale(double value) {
    if (_textScale != value) {
      _textScale = value;
      notifyListeners();
      if (value == null) {
        Store.sp.remove(StoreKeys.TEXT_SCALE);
      } else {
        Store.sp.setDouble(StoreKeys.TEXT_SCALE, value);
      }
    }
  }
}
\ No newline at end of file

M lib/pages/article_page.dart => lib/pages/article_page.dart +2 -1
@@ 53,7 53,8 @@ class ArticlePageState extends State<ArticlePage> {

  Future<NavigationDecision> _onNavigate(NavigationRequest request) async {
    if (navigated && request.isForMainFrame) {
      await launch(request.url);
      final internal = Global.globalModel.inAppBrowser;
      await launch(request.url, forceSafariVC: internal, forceWebView: internal);
      return NavigationDecision.prevent;
    } else {
      return NavigationDecision.navigate;

M lib/pages/group_list_page.dart => lib/pages/group_list_page.dart +1 -1
@@ 43,7 43,7 @@ class _GroupListPageState extends State<GroupListPage> {
        return SliverToBoxAdapter(child: MyListTile(
          title: Text(S.of(context).allSubscriptions),
          trailing: count > 0 ? Badge(count) : null,
          onTap: () { Navigator.of(context).pop(List<String>()); },
          onTap: () { Navigator.of(context).pop(List<String>.empty()); },
          background: CupertinoColors.systemBackground,
        ));
      },

M lib/pages/settings/general_page.dart => lib/pages/settings/general_page.dart +47 -2
@@ 16,6 16,7 @@ class GeneralPage extends StatefulWidget {

class _GeneralPageState extends State<GeneralPage> {
  bool _clearingCache = false;
  double textScale;

  void _clearCache() async {
    setState(() { _clearingCache = true; });


@@ 32,9 33,41 @@ class _GeneralPageState extends State<GeneralPage> {
    ),
    child: Consumer<GlobalModel>(
      builder: (context, globalModel, child) {
        final useSystemTextScale = globalModel.textScale == null;
        final textScaleItems = ListTileGroup([
          MyListTile(
            title: Text(S.of(context).followSystem),
            trailing: CupertinoSwitch(
              value: useSystemTextScale,
              onChanged: (v) {
                textScale = null;
                globalModel.textScale = v ? null : 1;
              },
            ),
            trailingChevron: false,
            withDivider: !useSystemTextScale,
          ),
          if (!useSystemTextScale) MyListTile(
            title: Expanded(child: CupertinoSlider(
              min: 0.5,
              max: 1.5,
              divisions: 8,
              value: textScale ?? globalModel.textScale,
              onChanged: (v) {
                setState(() { textScale = v; });
              },
              onChangeEnd: (v) {
                textScale = null;
                globalModel.textScale = v;
              },
            )),
            trailingChevron: false,
            withDivider: false,
          ),
        ], title: S.of(context).fontSize);
        final syncItems = ListTileGroup([
          MyListTile(
            title: Text(S.of(context).onStart),
            title: Text(S.of(context).syncOnStart),
            trailing: CupertinoSwitch(
              value: globalModel.syncOnStart,
              onChanged: (v) {


@@ 43,9 76,20 @@ class _GeneralPageState extends State<GeneralPage> {
              },
            ),
            trailingChevron: false,
          ),
          MyListTile(
            title: Text(S.of(context).inAppBrowser),
            trailing: CupertinoSwitch(
              value: globalModel.inAppBrowser,
              onChanged: (v) {
                globalModel.inAppBrowser = v;
                setState(() {});
              },
            ),
            trailingChevron: false,
            withDivider: false,
          ),
        ], title: S.of(context).sync);
        ], title: S.of(context).preferences);
        final storageItems = ListTileGroup([
          MyListTile(
            title: Text(S.of(context).clearCache),


@@ 97,6 141,7 @@ class _GeneralPageState extends State<GeneralPage> {
        return ListView(
          children: [
            syncItems,
            textScaleItems,
            storageItems,
            themeItems,
            localeItems,

M lib/pages/settings/services/feedbin_page.dart => lib/pages/settings/services/feedbin_page.dart +9 -1
@@ 1,3 1,5 @@
import 'dart:io';

import 'package:fluent_reader_lite/components/list_tile_group.dart';
import 'package:fluent_reader_lite/components/my_list_tile.dart';
import 'package:fluent_reader_lite/generated/l10n.dart';


@@ 123,6 125,7 @@ class _FeedbinPageState extends State<FeedbinPage> {
        DialogWidget.progress(style: DialogStyle.cupertino),
      );
      await Global.syncModel.removeService();
      _validating = false;
      DialogHelper().hide(context);
      final navigator = Navigator.of(context);
      while (navigator.canPop()) navigator.pop();


@@ 222,7 225,7 @@ class _FeedbinPageState extends State<FeedbinPage> {
        ], title: "");
      },
    );
    return CupertinoPageScaffold(
    final page = CupertinoPageScaffold(
      backgroundColor: MyColors.background,
      navigationBar: CupertinoNavigationBar(
        middle: Text("Feedbin"),


@@ 234,5 237,10 @@ class _FeedbinPageState extends State<FeedbinPage> {
        if (Global.service != null) logOutButton,
      ]),
    );
    if (Platform.isAndroid) {
      return WillPopScope(child: page, onWillPop: () async => !_validating);
    } else {
      return page;
    }
  }
}

M lib/pages/settings/services/fever_page.dart => lib/pages/settings/services/fever_page.dart +8 -1
@@ 1,4 1,5 @@
import 'dart:convert';
import 'dart:io';

import 'package:crypto/crypto.dart';
import 'package:fluent_reader_lite/components/list_tile_group.dart';


@@ 126,6 127,7 @@ class _FeverPageState extends State<FeverPage> {
        DialogWidget.progress(style: DialogStyle.cupertino),
      );
      await Global.syncModel.removeService();
      _validating = false;
      DialogHelper().hide(context);
      final navigator = Navigator.of(context);
      while (navigator.canPop()) navigator.pop();


@@ 223,7 225,7 @@ class _FeverPageState extends State<FeverPage> {
        ], title: "");
      },
    );
    return CupertinoPageScaffold(
    final page = CupertinoPageScaffold(
      backgroundColor: MyColors.background,
      navigationBar: CupertinoNavigationBar(
        middle: Text("Fever API"),


@@ 235,5 237,10 @@ class _FeverPageState extends State<FeverPage> {
        if (Global.service != null) logOutButton,
      ]),
    );
    if (Platform.isAndroid) {
      return WillPopScope(child: page, onWillPop: () async => !_validating);
    } else {
      return page;
    }
  }
}

M lib/utils/store.dart => lib/utils/store.dart +2 -0
@@ 12,6 12,8 @@ abstract class StoreKeys {
  static const LOCALE = "locale";
  static const KEEP_ITEMS_DAYS = "keepItemsD";
  static const SYNC_ON_START = "syncOnStart";
  static const IN_APP_BROWSER = "inAppBrowser";
  static const TEXT_SCALE = "textScale";

  // Feed preferences
  static const FEED_FILTER_ALL = "feedFilterA";