diff --git a/lib/component/app/app_type_component.dart b/lib/component/app/app_type_component.dart index 49328b0..36c0da6 100644 --- a/lib/component/app/app_type_component.dart +++ b/lib/component/app/app_type_component.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:nowser/const/app_type.dart'; -import '../../const/base.dart'; +import '../tag_component.dart'; class AppTypeComponent extends StatefulWidget { int appType; @@ -17,7 +17,6 @@ class AppTypeComponent extends StatefulWidget { class _AppTypeComponent extends State { @override Widget build(BuildContext context) { - var themeData = Theme.of(context); String typeName = "WEB"; if (widget.appType == AppType.ANDROID_APP) { typeName = "Android"; @@ -25,24 +24,6 @@ class _AppTypeComponent extends State { typeName = "Remote"; } - return Container( - decoration: BoxDecoration( - color: themeData.hintColor.withOpacity(0.3), - borderRadius: BorderRadius.circular(8), - ), - padding: EdgeInsets.only( - left: Base.BASE_PADDING_HALF, - right: Base.BASE_PADDING_HALF, - top: 4, - bottom: 4, - ), - child: Text( - typeName, - style: TextStyle( - fontSize: themeData.textTheme.bodySmall!.fontSize, - color: themeData.hintColor, - ), - ), - ); + return TagComponent(typeName); } } diff --git a/lib/component/reload_inherited_widget.dart b/lib/component/reload_inherited_widget.dart new file mode 100644 index 0000000..ad79319 --- /dev/null +++ b/lib/component/reload_inherited_widget.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +class ReloadInheritedWidget extends InheritedWidget { + Function reload; + + ReloadInheritedWidget({ + required super.child, + required this.reload, + }); + + static ReloadInheritedWidget? of(BuildContext context) { + return context.dependOnInheritedWidgetOfExactType(); + } + + @override + bool updateShouldNotify(covariant InheritedWidget oldWidget) { + return false; + } +} diff --git a/lib/component/tag_component.dart b/lib/component/tag_component.dart new file mode 100644 index 0000000..72c44e0 --- /dev/null +++ b/lib/component/tag_component.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; + +import '../const/base.dart'; + +class TagComponent extends StatefulWidget { + String text; + + TagComponent(this.text); + + @override + State createState() { + return _TagComponent(); + } +} + +class _TagComponent extends State { + @override + Widget build(BuildContext context) { + var themeData = Theme.of(context); + return Container( + decoration: BoxDecoration( + color: themeData.hintColor.withOpacity(0.3), + borderRadius: BorderRadius.circular(8), + ), + padding: const EdgeInsets.only( + left: Base.BASE_PADDING_HALF, + right: Base.BASE_PADDING_HALF, + top: 4, + bottom: 4, + ), + child: Text( + widget.text, + style: TextStyle( + fontSize: themeData.textTheme.bodySmall!.fontSize, + color: themeData.hintColor, + ), + ), + ); + } +} diff --git a/lib/data/db.dart b/lib/data/db.dart index 64c0640..9694b9e 100644 --- a/lib/data/db.dart +++ b/lib/data/db.dart @@ -37,9 +37,14 @@ class DB { // init db db.execute( "create table app(id integer not null constraint app_pk primary key autoincrement,pubkey text not null,app_type integer not null,code text not null,name text,image text,connect_type integer not null,always_allow text,always_reject text,created_at integer not null,updated_at integer not null);"); + db.execute( "create table auth_log(id integer not null constraint auth_log_pk primary key autoincrement,app_id integer not null,auth_type integer not null,event_kind integer,title text,content text,auth_result integer not null,created_at integer not null);"); db.execute("create index auth_log_index on auth_log (app_id);"); + + db.execute( + "create table remote_signing_info(id integer not null constraint remote_signing_info_pk primary key autoincrement,app_id integer,local_pubkey text,remote_signer_key text,relays text,secret text,created_at integer,updated_at integer);"); + db.execute( "create table zap_log(id integer not null constraint zap_log_pk primary key autoincrement,app_id integer not null constraint zap_log_index unique,zap_type integer not null,num integer not null,created_at integer not null);"); db.execute("create index zap_log_index on zap_log (app_id);"); diff --git a/lib/data/remote_signing_info_db.dart b/lib/data/remote_signing_info_db.dart index c3b2ee6..1d79cb0 100644 --- a/lib/data/remote_signing_info_db.dart +++ b/lib/data/remote_signing_info_db.dart @@ -20,4 +20,23 @@ class RemoteSigningInfoDB { return null; } + + static Future> penddingRemoteSigningInfo( + {DatabaseExecutor? db}) async { + List objs = []; + + var since = + DateTime.now().millisecondsSinceEpoch ~/ 1000 - 60 * 60 * 24 * 3; + + db = await DB.getDB(db); + List> list = await db.rawQuery( + "select * from remote_signing_info where app_id is null and created_at > ?", + [since]); + for (var i = 0; i < list.length; i++) { + var json = list[i]; + objs.add(RemoteSigningInfo.fromJson(json)); + } + + return objs; + } } diff --git a/lib/main.dart b/lib/main.dart index b105495..d3efacb 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -61,6 +61,8 @@ Future main() async { settingProvider = futureResultList[0] as SettingProvider; webProvider = WebProvider(); remoteSigningProvider = RemoteSigningProvider(); + remoteSigningProvider.reload(); + remoteSigningProvider.reloadPenddingRemoteApps(); runApp(MyApp()); } diff --git a/lib/provider/app_provider.dart b/lib/provider/app_provider.dart index b7b77a0..ef6b41a 100644 --- a/lib/provider/app_provider.dart +++ b/lib/provider/app_provider.dart @@ -6,6 +6,8 @@ import 'package:nowser/data/app_db.dart'; import '../const/auth_result.dart'; import '../data/app.dart'; +import '../data/remote_signing_info.dart'; +import '../data/remote_signing_info_db.dart'; class AppProvider extends ChangeNotifier { List _list = []; diff --git a/lib/provider/remote_signing_provider.dart b/lib/provider/remote_signing_provider.dart index 3f15e3e..7bc70d4 100644 --- a/lib/provider/remote_signing_provider.dart +++ b/lib/provider/remote_signing_provider.dart @@ -29,7 +29,7 @@ class RemoteSigningProvider extends ChangeNotifier with PermissionCheckMixin { context = _context; } - // k - v ==> localPubkey - Relay + // localPubkey - Relay Map> relayMap = {}; // localPubkey - RemoteSigningInfo @@ -247,6 +247,22 @@ class RemoteSigningProvider extends ChangeNotifier with PermissionCheckMixin { } } + List _penddingRemoteApps = []; + + List get penddingRemoteApps => _penddingRemoteApps; + + void addRemoteSigningInfo(RemoteSigningInfo remoteSigningInfo) { + RemoteSigningInfoDB.insert(remoteSigningInfo); + reloadPenddingRemoteApps(); + notifyListeners(); + } + + Future reloadPenddingRemoteApps() async { + var list = await RemoteSigningInfoDB.penddingRemoteSigningInfo(); + _penddingRemoteApps = list; + notifyListeners(); + } + /** * The below code is design for relay n - remoteSignerKey n */ diff --git a/lib/router/apps/add_remote_app_router.dart b/lib/router/apps/add_remote_app_router.dart index cb6ccfc..9bef8d2 100644 --- a/lib/router/apps/add_remote_app_router.dart +++ b/lib/router/apps/add_remote_app_router.dart @@ -7,6 +7,7 @@ import 'package:nostr_sdk/utils/string_util.dart'; import 'package:nowser/component/qrscanner.dart'; import 'package:nowser/data/remote_signing_info.dart'; import 'package:nowser/data/remote_signing_info_db.dart'; +import 'package:nowser/main.dart'; import 'package:nowser/util/router_util.dart'; import 'package:provider/provider.dart'; @@ -267,7 +268,7 @@ class _AddRemoteAppRouter extends State { } remoteSigningInfo.remoteSignerKey = generatePrivateKey(); - remoteSigningInfo.createdAt = DateTime.now().millisecondsSinceEpoch ~/ 10; + remoteSigningInfo.createdAt = DateTime.now().millisecondsSinceEpoch ~/ 1000; remoteSigningInfo.updatedAt = remoteSigningInfo.createdAt; // TODO @@ -304,11 +305,11 @@ class _AddRemoteAppRouter extends State { remoteSignerKey: remoteSignerKey, relays: relays.join(","), secret: secretController.text, - createdAt: DateTime.now().millisecondsSinceEpoch ~/ 10, + createdAt: DateTime.now().millisecondsSinceEpoch ~/ 1000, ); remoteSigningInfo.updatedAt = remoteSigningInfo.createdAt; - RemoteSigningInfoDB.insert(remoteSigningInfo); + remoteSigningProvider.addRemoteSigningInfo(remoteSigningInfo); RouterUtil.back(context); } diff --git a/lib/router/apps/apps_router.dart b/lib/router/apps/apps_router.dart index 8654156..4d2f15c 100644 --- a/lib/router/apps/apps_router.dart +++ b/lib/router/apps/apps_router.dart @@ -1,11 +1,23 @@ import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:nostr_sdk/client_utils/keys.dart'; +import 'package:nostr_sdk/nip19/nip19.dart'; +import 'package:nostr_sdk/utils/string_util.dart'; +import 'package:nostr_sdk/utils/date_format_util.dart'; +import 'package:nowser/component/cust_state.dart'; +import 'package:nowser/component/tag_component.dart'; +import 'package:nowser/const/app_type.dart'; import 'package:nowser/const/router_path.dart'; +import 'package:nowser/data/remote_signing_info_db.dart'; +import 'package:nowser/main.dart'; import 'package:nowser/provider/app_provider.dart'; import 'package:nowser/util/router_util.dart'; import 'package:provider/provider.dart'; +import '../../component/app/app_type_component.dart'; import '../../component/appbar_back_btn_component.dart'; import '../../const/base.dart'; +import '../../data/remote_signing_info.dart'; import '../me/me_router_app_item_component.dart'; class AppsRouter extends StatefulWidget { @@ -15,26 +27,121 @@ class AppsRouter extends StatefulWidget { } } -class _AppsRouter extends State { +class _AppsRouter extends CustState { @override - Widget build(BuildContext context) { + Widget doBuild(BuildContext context) { var themeData = Theme.of(context); var _appProvider = Provider.of(context); var appList = _appProvider.appList; - var main = ListView.builder( - itemBuilder: (context, index) { - if (index >= appList.length) { - return null; + List mainList = []; + + if (appList.isNotEmpty) { + List widgets = []; + var length = appList.length; + for (var i = 0; i < length; i++) { + var app = appList[i]; + widgets.add(Container( + child: MeRouterAppItemComponent(app), + )); + if (i + 1 < length) { + widgets.add(Divider()); + } + } + if (widgets.isNotEmpty) { + var listWidget = Container( + padding: EdgeInsets.all(Base.BASE_PADDING), + decoration: BoxDecoration( + color: themeData.cardColor, + borderRadius: BorderRadius.circular( + Base.BASE_PADDING, + ), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: widgets, + ), + ); + + mainList.add(SliverToBoxAdapter(child: listWidget)); + } + } + + List penddingList = + remoteSigningProvider.penddingRemoteApps; + if (penddingList.isNotEmpty) { + List widgets = []; + var length = penddingList.length; + for (var i = 0; i < length; i++) { + var remoteSigningInfo = penddingList[i]; + var pubkey = getPublicKey(remoteSigningInfo.remoteSignerKey!); + + String connectUrlType = "bunker"; + if (StringUtil.isNotBlank(remoteSigningInfo.localPubkey)) { + connectUrlType = "nostrconnect"; } - var app = appList[index]; - return Container( - child: MeRouterAppItemComponent(app), + widgets.add(Container( + child: Row( + children: [ + Text(Nip19.encodeSimplePubKey(pubkey)), + Expanded( + child: Container( + margin: EdgeInsets.only(left: Base.BASE_PADDING_HALF), + child: Text( + DateFormatUtil.format( + remoteSigningInfo.createdAt!, + ), + style: TextStyle( + color: themeData.hintColor, + ), + ), + )), + Container( + margin: const EdgeInsets.only(right: Base.BASE_PADDING), + child: TagComponent(connectUrlType), + ), + AppTypeComponent(AppType.REMOTE), + ], + ), + )); + + if (i + 1 < length) { + widgets.add(Divider()); + } + } + + if (widgets.isNotEmpty) { + mainList.add(SliverToBoxAdapter( + child: Container( + margin: EdgeInsets.only(top: Base.BASE_PADDING), + child: Text( + "Pendding connect remote apps", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + ), + )); + + var listWidget = Container( + margin: EdgeInsets.only(top: Base.BASE_PADDING), + padding: EdgeInsets.all(Base.BASE_PADDING), + decoration: BoxDecoration( + color: themeData.cardColor, + borderRadius: BorderRadius.circular( + Base.BASE_PADDING, + ), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: widgets, + ), ); - }, - itemCount: appList.length, - ); + + mainList.add(SliverToBoxAdapter(child: listWidget)); + } + } return Scaffold( appBar: AppBar( @@ -55,9 +162,18 @@ class _AppsRouter extends State { padding: const EdgeInsets.all(Base.BASE_PADDING), child: Icon(Icons.add), ), - ) + ), ], ), + body: Container( + padding: const EdgeInsets.all(Base.BASE_PADDING), + child: CustomScrollView( + slivers: mainList, + ), + ), ); } + + @override + Future onReady(BuildContext context) async {} } diff --git a/packages/nostr_sdk b/packages/nostr_sdk index d4aecb8..456da4a 160000 --- a/packages/nostr_sdk +++ b/packages/nostr_sdk @@ -1 +1 @@ -Subproject commit d4aecb8dd13e593d6049b533222c1ef216ffab43 +Subproject commit 456da4ab2dc1424d3e0a09e61c6c617c82068d24