diff --git a/lib/provider/web_provider.dart b/lib/provider/web_provider.dart index 2e49cee..60c5a44 100644 --- a/lib/provider/web_provider.dart +++ b/lib/provider/web_provider.dart @@ -4,10 +4,12 @@ import 'package:nostr_sdk/utils/string_util.dart'; import 'package:nowser/data/bookmark_db.dart'; import 'package:nowser/util/router_util.dart'; +import '../component/webview/web_home_component.dart'; import '../component/webview/web_info.dart'; import '../data/bookmark.dart'; import '../data/browser_history.dart'; import '../data/browser_history_db.dart'; +import '../router/index/index_web_component.dart'; class WebProvider extends ChangeNotifier { int index = 0; @@ -28,6 +30,8 @@ class WebProvider extends ChangeNotifier { void checkBlank() { if (webInfos.isEmpty) { webInfos.add(WebInfo(_rndId(), "")); + // webInfos.add(WebInfo(_rndId(), "https://www.oschina.net/")); + // webInfos.add(WebInfo(_rndId(), "https://github.com/")); } } @@ -39,7 +43,7 @@ class WebProvider extends ChangeNotifier { for (var i = 0; i < webInfos.length; i++) { var owi = webInfos[i]; if (owi.id == webInfo.id) { - webInfos[i] = webInfo.clone(); + webInfos[i] = webInfo; break; } } @@ -55,6 +59,7 @@ class WebProvider extends ChangeNotifier { webInfo.url = ""; webInfo.title = null; webInfo.controller = null; + webInfo.browserHistory = null; updateWebInfo(webInfo); } @@ -100,6 +105,7 @@ class WebProvider extends ChangeNotifier { index--; } + indexWebviews.remove(webInfo.id); webInfos.removeAt(i); checkBlank(); notifyListeners(); @@ -128,10 +134,14 @@ class WebProvider extends ChangeNotifier { url: url.toString(), createdAt: DateTime.now().millisecondsSinceEpoch ~/ 1000, ); - - BrowserHistoryDB.insert(browserHistory); + if (webInfo.browserHistory != null && + webInfo.browserHistory!.url == url.toString()) { + return; + } webInfo.browserHistory = browserHistory; + BrowserHistoryDB.insert(browserHistory); + updateWebInfo(webInfo); } catch (e) {} } @@ -191,7 +201,6 @@ class WebProvider extends ChangeNotifier { webInfo.controller!.loadUrl(urlRequest: URLRequest(url: WebUri(url))); return true; } else { - webInfo.clone(); updateWebInfo(webInfo); notifyListeners(); return true; @@ -200,6 +209,27 @@ class WebProvider extends ChangeNotifier { return false; } + + Map indexWebviews = {}; + + List getIndexWebviews(BuildContext context, Function showControl) { + List list = []; + for (var webInfo in webInfos) { + if (StringUtil.isBlank(webInfo.url)) { + list.add(WebHomeComponent(webInfo)); + } else { + var indexWebComp = indexWebviews[webInfo.id]; + if (indexWebComp == null) { + indexWebComp = + IndexWebComponent(webInfo, showControl, key: GlobalKey()); + indexWebviews[webInfo.id] = indexWebComp; + } + + list.add(indexWebComp); + } + } + return list; + } } class WebNumInfo { diff --git a/lib/router/index/index_router.dart b/lib/router/index/index_router.dart index d60b5b6..cc7dc73 100644 --- a/lib/router/index/index_router.dart +++ b/lib/router/index/index_router.dart @@ -1,6 +1,11 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:nostr_sdk/utils/platform_util.dart'; +import 'package:nostr_sdk/utils/string_util.dart'; import 'package:nowser/component/cust_state.dart'; +import 'package:nowser/component/image_component.dart'; +import 'package:nowser/component/webview/web_home_component.dart'; import 'package:nowser/main.dart'; import 'package:nowser/provider/web_provider.dart'; import 'package:nowser/router/index/index_web_component.dart'; @@ -23,7 +28,10 @@ class _IndexRouter extends CustState with PermissionCheckMixin, AndroidSignerMixin { final GlobalKey _scaffoldKey = new GlobalKey(); - Map webViewComponentMap = {}; + @override + void initState() { + super.initState(); + } @override Future onReady(BuildContext context) async { @@ -41,19 +49,12 @@ class _IndexRouter extends CustState remoteSigningProvider.updateContext(context); webProvider.checkBlank(); - var main = Selector( - builder: (context, webNumInfo, child) { - List list = []; - for (var i = 0; i < webNumInfo.length; i++) { - list.add(IndexWebComponent(i, showControl)); - } - return IndexedStack( - index: webNumInfo.index, - children: list, - ); - }, selector: (context, provider) { - return provider.getWebNumInfo(); - }); + var _webProvider = Provider.of(context); + + var main = IndexedStack( + index: _webProvider.index, + children: _webProvider.getIndexWebviews(context, showControl), + ); return PopScope( canPop: false, diff --git a/lib/router/index/index_web_component.dart b/lib/router/index/index_web_component.dart index 6215bf8..09c4a01 100644 --- a/lib/router/index/index_web_component.dart +++ b/lib/router/index/index_web_component.dart @@ -15,11 +15,12 @@ import '../../component/webview/webview_number_component.dart'; import 'web_control_component.dart'; class IndexWebComponent extends StatefulWidget { - int index; + WebInfo webInfo; Function showControl; - IndexWebComponent(this.index, this.showControl); + IndexWebComponent(this.webInfo, this.showControl, {required GlobalKey key}) + : super(key: key); @override State createState() { @@ -30,6 +31,18 @@ class IndexWebComponent extends StatefulWidget { class _IndexWebComponent extends State { static const double BOTTOM_BTN_PADDING = 10; + @override + void initState() { + super.initState(); + // print("indexWebComp initState ${widget.webInfo.id}"); + } + + @override + void dispose() { + super.dispose(); + // print("indexWebComp dispose ${widget.webInfo.id}"); + } + @override Widget build(BuildContext context) { var mediaQuery = MediaQuery.of(context); @@ -38,120 +51,120 @@ class _IndexWebComponent extends State { var titleWidth = maxWidth / 2; Widget numberWidget = WebViewNumberComponent(); + var webInfo = widget.webInfo; + + if (StringUtil.isBlank(webInfo.url)) { + return WebHomeComponent(webInfo); + } + + var webComp = WebViewComponent( + webInfo, + (webInfo, controller) { + webInfo.controller = controller; + webProvider.updateWebInfo(webInfo); + }, + onTitleChanged, + (webInfo, controller) { + webInfo.controller = controller; + webProvider.onLoadStop(webInfo); + }); + + String title = ""; + if (StringUtil.isNotBlank(webInfo.title)) { + title = webInfo.title!; + } else if (StringUtil.isNotBlank(webInfo.url)) { + title = webInfo.url; + } + + var main = Column( + children: [ + Expanded(child: webComp), + Container( + height: 60, + child: Row( + children: [ + wrapBottomBtn(const Icon(Icons.home_filled), left: 13, right: 8, + onTap: () { + webProvider.goHome(webInfo); + }), + wrapBottomBtn(numberWidget, left: 8, right: 8, onTap: () { + RouterUtil.router(context, RouterPath.WEB_TABS); + }), + Expanded( + child: Hero( + tag: "urlInput", + child: Material( + child: GestureDetector( + onTap: () async { + if (webInfo.controller == null) { + return; + } + + var url = await webInfo.controller!.getUrl(); + var value = await RouterUtil.router( + context, RouterPath.WEB_URL_INPUT, url.toString()); + if (value != null && value is String) { + webProvider.goTo(webInfo, value); + } + }, + behavior: HitTestBehavior.translucent, + child: Container( + margin: const EdgeInsets.only( + left: 8, + right: 8, + ), + decoration: BoxDecoration( + border: Border.all(), + borderRadius: + BorderRadius.circular(Base.BASE_PADDING_HALF), + ), + padding: const EdgeInsets.only( + left: Base.BASE_PADDING, + right: Base.BASE_PADDING, + top: Base.BASE_PADDING_HALF, + bottom: Base.BASE_PADDING_HALF, + ), + width: titleWidth, + child: Text( + title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), + ), + ), + ), + ), + wrapBottomBtn(const Icon(Icons.space_dashboard), onTap: () { + widget.showControl(); + }, left: 8, right: 8), + wrapBottomBtn(const Icon(Icons.segment), left: 8, right: 13, + onTap: () { + RouterUtil.router(context, RouterPath.ME); + }), + ], + ), + ), + ], + ); return Container( padding: EdgeInsets.only( top: padding.top, bottom: padding.bottom, ), - child: Selector( - builder: (context, webInfo, child) { - if (webInfo == null || StringUtil.isBlank(webInfo.url)) { - if (webInfo == null) { - return Container(); - } - - return WebHomeComponent(webInfo); - } - - var main = WebViewComponent(webInfo, (webInfo, controller) { - webInfo.controller = controller; - webProvider.updateWebInfo(webInfo); - }, (webInfo, controller, title) { - webInfo.controller = controller; - webInfo.title = title; - webProvider.updateWebInfo(webInfo); - }, (webInfo, controller) { - webInfo.controller = controller; - webProvider.onLoadStop(webInfo); - }); - - String title = ""; - if (StringUtil.isNotBlank(webInfo.title)) { - title = webInfo.title!; - } else if (StringUtil.isNotBlank(webInfo.url)) { - title = webInfo.url; - } - - return Column( - children: [ - Expanded(child: main), - Container( - height: 60, - child: Row( - children: [ - wrapBottomBtn(const Icon(Icons.home_filled), - left: 13, right: 8, onTap: () { - webProvider.goHome(webInfo); - }), - wrapBottomBtn(numberWidget, left: 8, right: 8, onTap: () { - RouterUtil.router(context, RouterPath.WEB_TABS); - }), - Expanded( - child: Hero( - tag: "urlInput", - child: Material( - child: GestureDetector( - onTap: () async { - if (webInfo.controller == null) { - return; - } - - var url = await webInfo.controller!.getUrl(); - var value = await RouterUtil.router(context, - RouterPath.WEB_URL_INPUT, url.toString()); - if (value != null && value is String) { - webProvider.goTo(webInfo, value); - } - }, - behavior: HitTestBehavior.translucent, - child: Container( - margin: const EdgeInsets.only( - left: 8, - right: 8, - ), - decoration: BoxDecoration( - border: Border.all(), - borderRadius: BorderRadius.circular( - Base.BASE_PADDING_HALF), - ), - padding: const EdgeInsets.only( - left: Base.BASE_PADDING, - right: Base.BASE_PADDING, - top: Base.BASE_PADDING_HALF, - bottom: Base.BASE_PADDING_HALF, - ), - width: titleWidth, - child: Text( - title, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), - ), - ), - ), - ), - wrapBottomBtn(const Icon(Icons.space_dashboard), onTap: () { - widget.showControl(); - }, left: 8, right: 8), - wrapBottomBtn(const Icon(Icons.segment), left: 8, right: 13, - onTap: () { - RouterUtil.router(context, RouterPath.ME); - }), - ], - ), - ), - ], - ); - }, - selector: (context, provider) { - return provider.getWebInfo(widget.index); - }, - ), + child: main, ); } + void onTitleChanged( + WebInfo webInfo, InAppWebViewController controller, String? title) { + webInfo.controller = controller; + webInfo.title = title; + webProvider.updateWebInfo(webInfo); + setState(() {}); + } + Widget wrapBottomBtn(Widget btn, {double left = 10, double right = 10, Function? onTap}) { return GestureDetector(