~cytrogen/fluent-reader-mobile

f746c4b51e50ee21bbd29fd500de130f4b17870e — Bruce Liu 5 years ago 2dedfb7
use jaguar to serve resources
M assets/article/article.js => assets/article/article.js +46 -47
@@ 1,53 1,52 @@
function r(params) {
    function get(name) {
        if (name = (new RegExp('[?&]' + encodeURIComponent(name) + '=([^&]*)')).exec(params))
            return decodeURIComponent(name[1])
        return null
function get(name) {
    if (name = (new RegExp('[?&]' + encodeURIComponent(name) + '=([^&]*)')).exec(location.search))
        return decodeURIComponent(name[1])
    return null
}
async function getArticle(url) {
    let article = get("a")
    if (get("m") === "1") {
        return (await Mercury.parse(url, {html: article})).content || ""
    } else {
        return article
    }
    async function getArticle(url) {
        let article = get("a")
        if (get("m") === "1") {
            return (await Mercury.parse(url, {html: article})).content || ""
        } else {
            return article
        }
}
document.documentElement.style.fontSize = get("s") + "px"
let theme = get("t")
if (theme !== null) document.documentElement.classList.add(theme === "1" ? "light" : "dark")
let url = get("u")
getArticle(url).then(article => {
    let domParser = new DOMParser()
    let dom = domParser.parseFromString(get("h"), "text/html")
    dom.getElementsByTagName("article")[0].innerHTML = article
    let baseUrl = url.split("/").slice(0, 3).join("/")
    for (let s of dom.getElementsByTagName("script")) {
        s.parentNode.removeChild(s)
    }
    document.documentElement.style.fontSize = get("s") + "px"
    let theme = get("t")
    if (theme !== null) document.documentElement.classList.add(theme === "1" ? "light" : "dark")
    let url = get("u")
    getArticle(url).then(article => {
        let domParser = new DOMParser()
        let dom = domParser.parseFromString(get("h"), "text/html")
        dom.getElementsByTagName("article")[0].innerHTML = article
        let baseUrl = url.split("/").slice(0, 3).join("/")
        for (let s of dom.getElementsByTagName("script")) {
            s.parentNode.removeChild(s)
        }
        for (let e of dom.querySelectorAll("*[src]")) {
            if (e.src && !e.src.startsWith("http")) {
                if (e.src.startsWith("/")) {
                    e.src = baseUrl + e.src
                } else if (e.src.startsWith(":")) {
                    e.src = "http" + e.src
                } else {
                    e.src = baseUrl + "/" + e.src
                }
    for (let e of dom.querySelectorAll("*[src]")) {
        if (e.src && !e.src.startsWith("http")) {
            if (e.src.startsWith("/")) {
                e.src = baseUrl + e.src
            } else if (e.src.startsWith(":")) {
                e.src = "http" + e.src
            } else {
                e.src = baseUrl + "/" + e.src
            }
        }
        for (let e of dom.querySelectorAll("*[href]")) {
            if (e.href && !e.href.startsWith("http")) {
                if (e.href.startsWith("/")) {
                    e.href = baseUrl + e.href
                } else if (e.href.startsWith(":")) {
                    e.href = "http" + e.href
                } else {
                    e.href = baseUrl + "/" + e.href
                }
    }
    for (let e of dom.querySelectorAll("*[href]")) {
        if (e.href && !e.href.startsWith("http")) {
            if (e.href.startsWith("/")) {
                e.href = baseUrl + e.href
            } else if (e.href.startsWith(":")) {
                e.href = "http" + e.href
            } else {
                e.href = baseUrl + "/" + e.href
            }
        }
        let main = document.getElementById("main")
        main.innerHTML = dom.body.innerHTML
        main.classList.add("show")
    })
}
    }
    let main = document.getElementById("main")
    main.innerHTML = dom.body.innerHTML
    main.classList.add("show")
})


M ios/Podfile.lock => ios/Podfile.lock +6 -6
@@ 1,7 1,5 @@
PODS:
  - Flutter (1.0.0)
  - flutter_inappwebview (0.0.1):
    - Flutter
  - FMDB (2.7.5):
    - FMDB/standard (= 2.7.5)
  - FMDB/standard (2.7.5)


@@ 18,16 16,18 @@ PODS:
    - FMDB (>= 2.7.5)
  - url_launcher (0.0.1):
    - Flutter
  - webview_flutter (0.0.1):
    - Flutter

DEPENDENCIES:
  - Flutter (from `Flutter`)
  - flutter_inappwebview (from `.symlinks/plugins/flutter_inappwebview/ios`)
  - package_info (from `.symlinks/plugins/package_info/ios`)
  - path_provider (from `.symlinks/plugins/path_provider/ios`)
  - share (from `.symlinks/plugins/share/ios`)
  - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
  - sqflite (from `.symlinks/plugins/sqflite/ios`)
  - url_launcher (from `.symlinks/plugins/url_launcher/ios`)
  - webview_flutter (from `.symlinks/plugins/webview_flutter/ios`)

SPEC REPOS:
  trunk:


@@ 36,8 36,6 @@ SPEC REPOS:
EXTERNAL SOURCES:
  Flutter:
    :path: Flutter
  flutter_inappwebview:
    :path: ".symlinks/plugins/flutter_inappwebview/ios"
  package_info:
    :path: ".symlinks/plugins/package_info/ios"
  path_provider:


@@ 50,10 48,11 @@ EXTERNAL SOURCES:
    :path: ".symlinks/plugins/sqflite/ios"
  url_launcher:
    :path: ".symlinks/plugins/url_launcher/ios"
  webview_flutter:
    :path: ".symlinks/plugins/webview_flutter/ios"

SPEC CHECKSUMS:
  Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
  flutter_inappwebview: 69dfbac46157b336ffbec19ca6dfd4638c7bf189
  FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
  package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
  path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c


@@ 61,6 60,7 @@ SPEC CHECKSUMS:
  shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
  sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
  url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
  webview_flutter: d2b4d6c66968ad042ad94cbb791f5b72b4678a96

PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c


M lib/main.dart => lib/main.dart +2 -0
@@ 22,6 22,7 @@ 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';
import 'generated/l10n.dart';
import 'models/global_model.dart';



@@ 33,6 34,7 @@ void main() async {
    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
      statusBarColor: Colors.transparent,
    ));
    WebView.platform = SurfaceAndroidWebView();
  }
  runApp(MyApp());
  SystemChannels.lifecycle.setMessageHandler((msg) {

M lib/pages/article_page.dart => lib/pages/article_page.dart +24 -40
@@ 11,7 11,6 @@ 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_inappwebview/flutter_inappwebview.dart';
import 'package:intl/intl.dart';
import 'package:http/http.dart' as http;
import 'package:provider/provider.dart';


@@ 19,6 18,7 @@ import 'package:tuple/tuple.dart';
import 'package:share/share.dart';
import 'package:fluent_reader_lite/components/cupertino_toolbar.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:webview_flutter/webview_flutter.dart';

class ArticlePage extends StatefulWidget {
  static final GlobalKey<ArticlePageState> state = GlobalKey();


@@ 30,22 30,13 @@ class ArticlePage extends StatefulWidget {
}

class ArticlePageState extends State<ArticlePage> {
  InAppWebViewController _controller;
  WebViewController _controller;
  int requestId = 0;
  bool loaded = false;
  bool navigated = false;
  SourceOpenTarget _target;
  String iid;
  bool isSourceFeed;
  String localParams;

  static final _webViewOptions = InAppWebViewGroupOptions(
    crossPlatform: InAppWebViewOptions(
      useShouldOverrideUrlLoading: true,
      debuggingEnabled: true,
      transparentBackground: true,
    ),
  );

  void loadNewItem(String id, {bool isSource}) {
    if (!Global.itemsModel.getItem(id).hasRead) {


@@ 60,21 51,17 @@ class ArticlePageState extends State<ArticlePage> {
    });
  }

  Future<bool> _onNewWindow(_, CreateWindowRequest request) async {
    await launch(request.url);
    return false;
  }

  Future<ShouldOverrideUrlLoadingAction> _onNavigate(_, ShouldOverrideUrlLoadingRequest request) async {
  Future<NavigationDecision> _onNavigate(NavigationRequest request) async {
    if (navigated && request.isForMainFrame) {
      await launch(request.url);
      return ShouldOverrideUrlLoadingAction.CANCEL;
      return NavigationDecision.prevent;
    } else {
      return NavigationDecision.navigate;
    }
    return ShouldOverrideUrlLoadingAction.ALLOW;
  }

  void _loadHtml(RSSItem item, RSSSource source, {loadFull: false}) async {
    var localUrl = "assets/article/article.html";
    var localUrl = "http://127.0.0.1:9000/article/article.html";
    var currId = requestId;
    String a;
    if (loadFull) {


@@ 94,23 81,22 @@ class ArticlePageState extends State<ArticlePage> {
    h += '<article></article>';
    h = Uri.encodeComponent(h);
    var s = Store.getArticleFontSize();
    localParams = "?a=$a&h=$h&s=$s&u=${item.link}&m=${loadFull ? 1 : 0}";
    localUrl += "?a=$a&h=$h&s=$s&u=${item.link}&m=${loadFull ? 1 : 0}";
    if (Platform.isAndroid || Global.globalModel.getBrightness() != null) {
      var brightness = Global.currentBrightness(context);
      localParams += "&t=${brightness.index}";
      localUrl += "&t=${brightness.index}";
    }
    if (currId == requestId) _controller.loadFile(assetFilePath: localUrl);
    
    if (currId == requestId) _controller.loadUrl(localUrl);
  }

  void _onPageReady(_, String url) async {
    if (url != "about:blank") {
      if (localParams != null) {
        _controller.evaluateJavascript(source: 'r("$localParams")');
        setState(() { loaded = true; });
      }
      navigated = true;
  void _onPageReady(_) async {
    if (Platform.isAndroid || Global.globalModel.getBrightness() != null) {
      await Future.delayed(Duration(milliseconds: 300));
    }
    setState(() { loaded = true; });
  }
  void _onWebpageReady(_) {
    if (loaded) navigated = true;
  }

  void _setOpenTarget(RSSSource source, {SourceOpenTarget target}) {


@@ 134,9 120,7 @@ class ArticlePageState extends State<ArticlePage> {
        break;
      case SourceOpenTarget.Webpage:
      case SourceOpenTarget.External:
        localParams = null;
        _controller.loadUrl(url: item.link);
        setState(() { loaded = true; });
        _controller.loadUrl(item.link);
        break;
    }
  }


@@ 168,16 152,16 @@ class ArticlePageState extends State<ArticlePage> {
            Center(
              child: CupertinoActivityIndicator()
            ),
            InAppWebView(
            WebView(
              key: Key("a-$iid-${_target.index}"),
              onWebViewCreated: (InAppWebViewController webViewController) {
              javascriptMode: JavascriptMode.unrestricted,
              onWebViewCreated: (WebViewController webViewController) {
                _controller = webViewController;
                _loadOpenTarget(item, source);
              },
              onLoadStop: _onPageReady,
              onCreateWindow: _onNewWindow,
              shouldOverrideUrlLoading: _onNavigate,
              initialOptions: _webViewOptions,
              onPageStarted: _onPageReady,
              onPageFinished: _onWebpageReady,
              navigationDelegate: _onNavigate,
            ),
          ],
        ), bottom: false,);

M lib/pages/settings/services/feedbin_page.dart => lib/pages/settings/services/feedbin_page.dart +2 -0
@@ 84,6 84,7 @@ class _FeedbinPageState extends State<FeedbinPage> {
      await Global.syncModel.syncWithService();
      Global.syncModel.checkHasService();
      _validating = false;
      DialogHelper().hide(context);
      if (mounted) Navigator.of(context).pop();
    } else {
      setState(() { _validating = false; });


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

M lib/pages/settings/services/fever_page.dart => lib/pages/settings/services/fever_page.dart +2 -0
@@ 87,6 87,7 @@ class _FeverPageState extends State<FeverPage> {
      await Global.syncModel.syncWithService();
      Global.syncModel.checkHasService();
      _validating = false;
      DialogHelper().hide(context);
      if (mounted) Navigator.of(context).pop();
    } else {
      setState(() { _validating = false; });


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

M lib/utils/global.dart => lib/utils/global.dart +6 -0
@@ 10,6 10,8 @@ import 'package:fluent_reader_lite/models/sync_model.dart';
import 'package:fluent_reader_lite/utils/db.dart';
import 'package:fluent_reader_lite/utils/store.dart';
import 'package:flutter/cupertino.dart';
import 'package:jaguar/serve/server.dart';
import 'package:jaguar_flutter_asset/jaguar_flutter_asset.dart';
import 'package:sqflite/sqflite.dart';

abstract class Global {


@@ 22,6 24,7 @@ abstract class Global {
  static SyncModel syncModel;
  static ServiceHandler service;
  static Database db;
  static Jaguar server;
  static final GlobalKey<NavigatorState> tabletPanel = GlobalKey();

  static void init() {


@@ 64,6 67,9 @@ abstract class Global {
          .millisecondsSinceEpoch,
      ],
    );
    server = Jaguar(address: "127.0.0.1",port: 9000);
    server.addRoute(serveFlutterAssets());
    await server.serve();
    await sourcesModel.init();
    await feedsModel.all.init();
    if (globalModel.syncOnStart) await syncModel.syncWithService();

M pubspec.lock => pubspec.lock +63 -7
@@ 22,6 22,13 @@ packages:
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.5.0-nullsafety.3"
  auth_header:
    dependency: transitive
    description:
      name: auth_header
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.1.4"
  boolean_selector:
    dependency: transitive
    description:


@@ 132,13 139,6 @@ packages:
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.1.0"
  flutter_inappwebview:
    dependency: "direct main"
    description:
      name: flutter_inappwebview
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "4.0.0+4"
  flutter_localizations:
    dependency: "direct main"
    description: flutter


@@ 175,6 175,13 @@ packages:
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "3.1.4"
  http_server:
    dependency: transitive
    description:
      name: http_server
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "0.9.8+3"
  image:
    dependency: transitive
    description:


@@ 189,6 196,34 @@ packages:
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "0.17.0-nullsafety.2"
  jaguar:
    dependency: "direct main"
    description:
      name: jaguar
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.4.46"
  jaguar_common:
    dependency: transitive
    description:
      name: jaguar_common
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.1.4"
  jaguar_flutter_asset:
    dependency: "direct main"
    description:
      name: jaguar_flutter_asset
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.2.0"
  jaguar_serializer:
    dependency: transitive
    description:
      name: jaguar_serializer
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.2.12"
  js:
    dependency: transitive
    description:


@@ 196,6 231,13 @@ packages:
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "0.6.3-nullsafety.3"
  logging:
    dependency: transitive
    description:
      name: logging
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "0.11.4"
  matcher:
    dependency: transitive
    description:


@@ 294,6 336,13 @@ packages:
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "0.0.4+3"
  path_tree:
    dependency: transitive
    description:
      name: path_tree
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.2.4"
  pedantic:
    dependency: transitive
    description:


@@ 544,6 593,13 @@ packages:
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.1.0-nullsafety.5"
  webview_flutter:
    dependency: "direct main"
    description:
      name: webview_flutter
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.0-nullsafety.3"
  win32:
    dependency: transitive
    description:

M pubspec.yaml => pubspec.yaml +3 -1
@@ 31,7 31,9 @@ dependencies:
  intl: ^0.17.0-nullsafety.2
  http: ^0.12.2
  html: ^0.14.0+4
  flutter_inappwebview: ^4.0.0+4
  webview_flutter: ^2.0.0-nullsafety.3
  jaguar: ^2.4.46
  jaguar_flutter_asset: ^2.2.0
  url_launcher: ^5.7.10
  sqflite: ^1.3.2+1
  path: ^1.7.0