diff --git a/lib/component/appbar_back_btn_component.dart b/lib/component/appbar_back_btn_component.dart new file mode 100644 index 0000000..12f749c --- /dev/null +++ b/lib/component/appbar_back_btn_component.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; + +import '../util/router_util.dart'; + +class AppbarBackBtnComponent extends StatefulWidget { + @override + State createState() { + return _AppbarBackBtnComponent(); + } +} + +class _AppbarBackBtnComponent extends State { + @override + Widget build(BuildContext context) { + var themeData = Theme.of(context); + + return GestureDetector( + onTap: () { + RouterUtil.back(context); + }, + child: Icon( + Icons.arrow_back_ios, + color: themeData.appBarTheme.titleTextStyle!.color, + ), + ); + } +} diff --git a/lib/component/text_input/text_input_dialog.dart b/lib/component/text_input/text_input_dialog.dart new file mode 100644 index 0000000..cfd7e22 --- /dev/null +++ b/lib/component/text_input/text_input_dialog.dart @@ -0,0 +1,73 @@ +import 'package:flutter/material.dart'; +import 'package:nostr_sdk/utils/string_util.dart'; + +import '../../../util/router_util.dart'; +import '../../const/base.dart'; +import 'text_input_dialog_inner_component.dart'; + +class TextInputDialog extends StatefulWidget { + String title; + + String? hintText; + + String? value; + + bool Function(BuildContext, String)? valueCheck; + + TextInputDialog( + this.title, { + this.hintText, + this.value, + this.valueCheck, + }); + + @override + State createState() { + return _TextInputDialog(); + } + + static Future show(BuildContext context, String title, + {String? value, + String? hintText, + bool Function(BuildContext, String)? valueCheck}) async { + return await showDialog( + context: context, + builder: (_context) { + return TextInputDialog( + StringUtil.breakWord(title), + hintText: hintText, + value: value, + valueCheck: valueCheck, + ); + }); + } +} + +class _TextInputDialog extends State { + @override + Widget build(BuildContext context) { + var themeData = Theme.of(context); + var main = TextInputDialogInnerComponent( + widget.title, + hintText: widget.hintText, + value: widget.value, + valueCheck: widget.valueCheck, + ); + + return Dialog( + child: FocusScope( + autofocus: true, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + RouterUtil.back(context); + }, + child: Container( + padding: EdgeInsets.all(Base.BASE_PADDING * 2), + child: main, + ), + ), + ), + ); + } +} diff --git a/lib/component/text_input/text_input_dialog_inner_component.dart b/lib/component/text_input/text_input_dialog_inner_component.dart new file mode 100644 index 0000000..a686d77 --- /dev/null +++ b/lib/component/text_input/text_input_dialog_inner_component.dart @@ -0,0 +1,106 @@ +import 'package:flutter/material.dart'; + +import '../../../generated/l10n.dart'; +import '../../../util/router_util.dart'; +import '../../const/base.dart'; + +class TextInputDialogInnerComponent extends StatefulWidget { + String title; + + String? hintText; + + String? value; + + bool Function(BuildContext, String)? valueCheck; + + TextInputDialogInnerComponent( + this.title, { + this.hintText, + this.value, + this.valueCheck, + }); + + @override + State createState() { + return _TextInputDialogInnerComponent(); + } +} + +class _TextInputDialogInnerComponent + extends State { + late TextEditingController controller; + + @override + void initState() { + super.initState(); + controller = TextEditingController(text: widget.value); + } + + @override + Widget build(BuildContext context) { + var themeData = Theme.of(context); + Color cardColor = themeData.cardColor; + var mainColor = themeData.primaryColor; + var titleFontSize = themeData.textTheme.bodyLarge!.fontSize; + + List list = []; + + list.add(Container( + margin: EdgeInsets.only(bottom: Base.BASE_PADDING), + child: Text( + widget.title, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: titleFontSize, + ), + ), + )); + + list.add(Container( + child: TextField( + controller: controller, + minLines: 4, + maxLines: 4, + autofocus: true, + decoration: InputDecoration( + hintText: widget.hintText, + border: OutlineInputBorder(borderSide: BorderSide(width: 1)), + ), + ), + )); + + list.add(Container( + margin: EdgeInsets.only(top: Base.BASE_PADDING), + width: double.infinity, + child: FilledButton( + onPressed: _onConfirm, + child: Text("Confirm"), + ), + )); + + var main = Container( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: list, + ), + ); + + return main; + } + + void _onConfirm() { + var value = controller.text; + // if (StringUtil.isBlank(value)) { + // BotToast.showText(text: "Input can't be null"); + // return; + // } + + if (widget.valueCheck != null) { + if (!widget.valueCheck!(context, value)) { + return; + } + } + return RouterUtil.back(context, value); + } +} diff --git a/lib/component/webview/web_home_component.dart b/lib/component/webview/web_home_component.dart index a5f7609..d5f95f2 100644 --- a/lib/component/webview/web_home_component.dart +++ b/lib/component/webview/web_home_component.dart @@ -61,7 +61,9 @@ class _WebHomeComponent extends State { ), onTap: () { RouterUtil.router(context, RouterPath.WEB_TABS); }), - wrapBottomBtn(const Icon(Icons.space_dashboard)), + wrapBottomBtn(const Icon(Icons.space_dashboard), onTap: () { + AuthDialog.show(context); + }), wrapBottomBtn(const Icon(Icons.segment), onTap: () { // AuthDialog.show(context); RouterUtil.router(context, RouterPath.ME); diff --git a/lib/const/router_path.dart b/lib/const/router_path.dart index 2106127..96088e0 100644 --- a/lib/const/router_path.dart +++ b/lib/const/router_path.dart @@ -2,4 +2,5 @@ class RouterPath { static const String INDEX = "/"; static const String WEB_TABS = "/webTabs"; static const String ME = "/me"; + static const String KEYS = "/keys"; } diff --git a/lib/main.dart b/lib/main.dart index 072d563..d8efcb7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -11,6 +11,7 @@ import 'package:nowser/data/db.dart'; import 'package:nowser/provider/key_provider.dart'; import 'package:nowser/provider/web_provider.dart'; import 'package:nowser/router/index/index_router.dart'; +import 'package:nowser/router/keys/keys_router.dart'; import 'package:nowser/router/me/me_router.dart'; import 'package:nowser/router/web_tabs_select/web_tabs_select_router.dart'; import 'package:provider/provider.dart'; @@ -77,6 +78,7 @@ class _MyApp extends State { RouterPath.INDEX: (context) => IndexRouter(), RouterPath.WEB_TABS: (context) => WebTabsSelectRouter(), RouterPath.ME: (context) => MeRouter(), + RouterPath.KEYS: (context) => KeysRouter(), }; return MultiProvider( diff --git a/lib/router/keys/keys_item_component.dart b/lib/router/keys/keys_item_component.dart new file mode 100644 index 0000000..4cd9fe6 --- /dev/null +++ b/lib/router/keys/keys_item_component.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; +import 'package:nostr_sdk/nip19/nip19.dart'; +import 'package:nowser/const/base.dart'; + +import '../../component/user_pic_component.dart'; + +class KeysItemComponent extends StatefulWidget { + bool isDefault; + + String pubkey; + + KeysItemComponent(this.pubkey, {this.isDefault = false}); + + @override + State createState() { + return _KeysItemComponent(); + } +} + +class _KeysItemComponent extends State { + @override + Widget build(BuildContext context) { + var themeData = Theme.of(context); + var mainColor = themeData.primaryColor; + List list = []; + + list.add(Container( + margin: EdgeInsets.only( + right: Base.BASE_PADDING_HALF, + ), + child: UserPicComponent( + width: 26, + ), + )); + list.add(Expanded( + child: Text( + Nip19.encodePubKey(widget.pubkey), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ))); + list.add(Container( + margin: EdgeInsets.only( + left: Base.BASE_PADDING_HALF, + // right: Base.BASE_PADDING_HALF, + ), + child: Icon(Icons.logout), + )); + + return Container( + padding: EdgeInsets.all(Base.BASE_PADDING), + decoration: BoxDecoration( + color: + widget.isDefault ? mainColor.withOpacity(0.5) : themeData.cardColor, + borderRadius: BorderRadius.circular(Base.BASE_PADDING), + ), + child: Row( + children: list, + ), + ); + } +} diff --git a/lib/router/keys/keys_router.dart b/lib/router/keys/keys_router.dart new file mode 100644 index 0000000..3baa0e0 --- /dev/null +++ b/lib/router/keys/keys_router.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:nowser/component/appbar_back_btn_component.dart'; +import 'package:nowser/component/text_input/text_input_dialog.dart'; +import 'package:nowser/const/base.dart'; +import 'package:nowser/router/keys/keys_item_component.dart'; + +class KeysRouter extends StatefulWidget { + @override + State createState() { + return _KeysRouter(); + } + + static void addKey(BuildContext context) { + TextInputDialog.show(context, "Please input private key"); + } +} + +class _KeysRouter extends State { + @override + Widget build(BuildContext context) { + var themeData = Theme.of(context); + var margin = EdgeInsets.only( + left: Base.BASE_PADDING, + right: Base.BASE_PADDING, + top: Base.BASE_PADDING, + ); + + List list = []; + list.add(Container( + margin: margin, + child: KeysItemComponent( + "29320975df855fe34a7b45ada2421e2c741c37c0136901fe477133a91eb18b07", + isDefault: true, + ), + )); + for (var i = 0; i < 5; i++) { + list.add(Container( + margin: margin, + child: KeysItemComponent( + "8fb140b4e8ddef97ce4b821d247278a1a4353362623f64021484b372f948000c", + ), + )); + } + + var main = ListView( + children: list, + ); + + return Scaffold( + appBar: AppBar( + leading: AppbarBackBtnComponent(), + title: Text( + "Keys Manager", + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: themeData.textTheme.bodyLarge!.fontSize, + ), + ), + actions: [ + GestureDetector( + onTap: () { + KeysRouter.addKey(context); + }, + child: Container( + padding: const EdgeInsets.all(Base.BASE_PADDING), + child: Icon(Icons.add), + ), + ) + ], + ), + body: main, + ); + } +} diff --git a/lib/router/me/me_router.dart b/lib/router/me/me_router.dart index c554824..9ee6a50 100644 --- a/lib/router/me/me_router.dart +++ b/lib/router/me/me_router.dart @@ -1,9 +1,13 @@ import 'package:flutter/material.dart'; +import 'package:nowser/component/text_input/text_input_dialog.dart'; import 'package:nowser/component/user_pic_component.dart'; import 'package:nowser/const/base.dart'; +import 'package:nowser/const/router_path.dart'; import 'package:nowser/router/me/me_router_log_item_component.dart'; import 'package:nowser/router/me/me_router_web_item_component.dart'; +import 'package:nowser/util/router_util.dart'; +import '../keys/keys_router.dart'; import 'me_router_app_item_component.dart'; class MeRouter extends StatefulWidget { @@ -33,7 +37,12 @@ class _MeRouter extends State { )); defaultUserWidgets.add(Container( margin: EdgeInsets.only(left: Base.BASE_PADDING), - child: Text("Click and Login"), + child: GestureDetector( + onTap: () { + KeysRouter.addKey(context); + }, + child: Text("Click and Login"), + ), )); defaultUserWidgets.add(Expanded(child: Container())); defaultUserWidgets.add(Container( @@ -69,33 +78,37 @@ class _MeRouter extends State { ), margin: listWidgetMargin, padding: EdgeInsets.all(Base.BASE_PADDING), - child: Row( - children: memberList, + child: GestureDetector( + onTap: () { + RouterUtil.router(context, RouterPath.KEYS); + }, + behavior: HitTestBehavior.translucent, + child: Row( + children: memberList, + ), ), ); List webItemList = []; webItemList.add(MeRouterWebItemComponent( num: 102, - name: "Bookmarks", - // margin: EdgeInsets.only(right: Base.BASE_PADDING), + name: "Bookmark", + iconData: Icons.bookmark, )); webItemList.add(MeRouterWebItemComponent( num: 999, - name: "Historys", - // margin: - // EdgeInsets.only(left: Base.BASE_PADDING, right: Base.BASE_PADDING), + name: "History", + iconData: Icons.history, )); webItemList.add(MeRouterWebItemComponent( num: 30, - name: "Downloads", - // margin: - // EdgeInsets.only(left: Base.BASE_PADDING, right: Base.BASE_PADDING), + name: "Download", + iconData: Icons.download, )); webItemList.add(MeRouterWebItemComponent( num: 102, - name: "Bookmarks", - // margin: EdgeInsets.only(left: Base.BASE_PADDING), + name: "Bookmark", + iconData: Icons.bookmark, )); var webItemWidget = Container( margin: listWidgetMargin, diff --git a/lib/router/me/me_router_web_item_component.dart b/lib/router/me/me_router_web_item_component.dart index b307cf2..0f12fa7 100644 --- a/lib/router/me/me_router_web_item_component.dart +++ b/lib/router/me/me_router_web_item_component.dart @@ -6,12 +6,12 @@ class MeRouterWebItemComponent extends StatefulWidget { String name; - // EdgeInsetsGeometry margin; + IconData iconData; MeRouterWebItemComponent({ required this.num, required this.name, - // required this.margin, + required this.iconData, }); @override @@ -44,15 +44,19 @@ class _MeRouterWebItemComponent extends State { child: Column( mainAxisSize: MainAxisSize.min, children: [ - Text( - "${widget.num}", - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), + Icon(widget.iconData), Text( widget.name, maxLines: 1, overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: themeData.textTheme.bodySmall!.fontSize! - 2, + ), + ), + Text( + "${widget.num}", + maxLines: 1, + overflow: TextOverflow.ellipsis, ), ], ),