This commit is contained in:
DASHU
2024-09-20 09:41:11 +08:00
parent ec0e357002
commit 535c5e6e17
3 changed files with 169 additions and 125 deletions

View File

@@ -4,10 +4,12 @@ import 'package:nostr_sdk/utils/string_util.dart';
import 'package:nowser/data/bookmark_db.dart'; import 'package:nowser/data/bookmark_db.dart';
import 'package:nowser/util/router_util.dart'; import 'package:nowser/util/router_util.dart';
import '../component/webview/web_home_component.dart';
import '../component/webview/web_info.dart'; import '../component/webview/web_info.dart';
import '../data/bookmark.dart'; import '../data/bookmark.dart';
import '../data/browser_history.dart'; import '../data/browser_history.dart';
import '../data/browser_history_db.dart'; import '../data/browser_history_db.dart';
import '../router/index/index_web_component.dart';
class WebProvider extends ChangeNotifier { class WebProvider extends ChangeNotifier {
int index = 0; int index = 0;
@@ -28,6 +30,8 @@ class WebProvider extends ChangeNotifier {
void checkBlank() { void checkBlank() {
if (webInfos.isEmpty) { if (webInfos.isEmpty) {
webInfos.add(WebInfo(_rndId(), "")); 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++) { for (var i = 0; i < webInfos.length; i++) {
var owi = webInfos[i]; var owi = webInfos[i];
if (owi.id == webInfo.id) { if (owi.id == webInfo.id) {
webInfos[i] = webInfo.clone(); webInfos[i] = webInfo;
break; break;
} }
} }
@@ -55,6 +59,7 @@ class WebProvider extends ChangeNotifier {
webInfo.url = ""; webInfo.url = "";
webInfo.title = null; webInfo.title = null;
webInfo.controller = null; webInfo.controller = null;
webInfo.browserHistory = null;
updateWebInfo(webInfo); updateWebInfo(webInfo);
} }
@@ -100,6 +105,7 @@ class WebProvider extends ChangeNotifier {
index--; index--;
} }
indexWebviews.remove(webInfo.id);
webInfos.removeAt(i); webInfos.removeAt(i);
checkBlank(); checkBlank();
notifyListeners(); notifyListeners();
@@ -128,10 +134,14 @@ class WebProvider extends ChangeNotifier {
url: url.toString(), url: url.toString(),
createdAt: DateTime.now().millisecondsSinceEpoch ~/ 1000, createdAt: DateTime.now().millisecondsSinceEpoch ~/ 1000,
); );
if (webInfo.browserHistory != null &&
BrowserHistoryDB.insert(browserHistory); webInfo.browserHistory!.url == url.toString()) {
return;
}
webInfo.browserHistory = browserHistory; webInfo.browserHistory = browserHistory;
BrowserHistoryDB.insert(browserHistory);
updateWebInfo(webInfo); updateWebInfo(webInfo);
} catch (e) {} } catch (e) {}
} }
@@ -191,7 +201,6 @@ class WebProvider extends ChangeNotifier {
webInfo.controller!.loadUrl(urlRequest: URLRequest(url: WebUri(url))); webInfo.controller!.loadUrl(urlRequest: URLRequest(url: WebUri(url)));
return true; return true;
} else { } else {
webInfo.clone();
updateWebInfo(webInfo); updateWebInfo(webInfo);
notifyListeners(); notifyListeners();
return true; return true;
@@ -200,6 +209,27 @@ class WebProvider extends ChangeNotifier {
return false; return false;
} }
Map<String, IndexWebComponent> indexWebviews = {};
List<Widget> getIndexWebviews(BuildContext context, Function showControl) {
List<Widget> 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 { class WebNumInfo {

View File

@@ -1,6 +1,11 @@
import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:nostr_sdk/utils/platform_util.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/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/main.dart';
import 'package:nowser/provider/web_provider.dart'; import 'package:nowser/provider/web_provider.dart';
import 'package:nowser/router/index/index_web_component.dart'; import 'package:nowser/router/index/index_web_component.dart';
@@ -23,7 +28,10 @@ class _IndexRouter extends CustState<IndexRouter>
with PermissionCheckMixin, AndroidSignerMixin { with PermissionCheckMixin, AndroidSignerMixin {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>(); final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
Map<String, WebViewComponent> webViewComponentMap = {}; @override
void initState() {
super.initState();
}
@override @override
Future<void> onReady(BuildContext context) async { Future<void> onReady(BuildContext context) async {
@@ -41,19 +49,12 @@ class _IndexRouter extends CustState<IndexRouter>
remoteSigningProvider.updateContext(context); remoteSigningProvider.updateContext(context);
webProvider.checkBlank(); webProvider.checkBlank();
var main = Selector<WebProvider, WebNumInfo>( var _webProvider = Provider.of<WebProvider>(context);
builder: (context, webNumInfo, child) {
List<Widget> list = []; var main = IndexedStack(
for (var i = 0; i < webNumInfo.length; i++) { index: _webProvider.index,
list.add(IndexWebComponent(i, showControl)); children: _webProvider.getIndexWebviews(context, showControl),
} );
return IndexedStack(
index: webNumInfo.index,
children: list,
);
}, selector: (context, provider) {
return provider.getWebNumInfo();
});
return PopScope( return PopScope(
canPop: false, canPop: false,

View File

@@ -15,11 +15,12 @@ import '../../component/webview/webview_number_component.dart';
import 'web_control_component.dart'; import 'web_control_component.dart';
class IndexWebComponent extends StatefulWidget { class IndexWebComponent extends StatefulWidget {
int index; WebInfo webInfo;
Function showControl; Function showControl;
IndexWebComponent(this.index, this.showControl); IndexWebComponent(this.webInfo, this.showControl, {required GlobalKey key})
: super(key: key);
@override @override
State<StatefulWidget> createState() { State<StatefulWidget> createState() {
@@ -30,6 +31,18 @@ class IndexWebComponent extends StatefulWidget {
class _IndexWebComponent extends State<IndexWebComponent> { class _IndexWebComponent extends State<IndexWebComponent> {
static const double BOTTOM_BTN_PADDING = 10; 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var mediaQuery = MediaQuery.of(context); var mediaQuery = MediaQuery.of(context);
@@ -38,120 +51,120 @@ class _IndexWebComponent extends State<IndexWebComponent> {
var titleWidth = maxWidth / 2; var titleWidth = maxWidth / 2;
Widget numberWidget = WebViewNumberComponent(); 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( return Container(
padding: EdgeInsets.only( padding: EdgeInsets.only(
top: padding.top, top: padding.top,
bottom: padding.bottom, bottom: padding.bottom,
), ),
child: Selector<WebProvider, WebInfo?>( child: main,
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);
},
),
); );
} }
void onTitleChanged(
WebInfo webInfo, InAppWebViewController controller, String? title) {
webInfo.controller = controller;
webInfo.title = title;
webProvider.updateWebInfo(webInfo);
setState(() {});
}
Widget wrapBottomBtn(Widget btn, Widget wrapBottomBtn(Widget btn,
{double left = 10, double right = 10, Function? onTap}) { {double left = 10, double right = 10, Function? onTap}) {
return GestureDetector( return GestureDetector(