From 40d616c8bd5cf3158dec316df71ada44b704b642 Mon Sep 17 00:00:00 2001 From: Dain Nilsson Date: Sun, 3 Apr 2022 11:03:03 +0200 Subject: [PATCH] AppPage improvements. - Make AppPage content scrollable. - Add optional FAB (with extra padding for FAB). - Add bottomMenu. --- lib/app/message.dart | 44 +++++++++++++++++++++++++++ lib/app/models.dart | 3 ++ lib/app/views/app_page.dart | 21 +++++++------ lib/app/views/device_info_screen.dart | 11 ++----- lib/app/views/main_page.dart | 2 +- lib/app/views/no_device_screen.dart | 31 +++++++++---------- 6 files changed, 78 insertions(+), 34 deletions(-) diff --git a/lib/app/message.dart b/lib/app/message.dart index 353e09b5..2d94d3b6 100755 --- a/lib/app/message.dart +++ b/lib/app/message.dart @@ -1,4 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'models.dart'; +import 'state.dart'; ScaffoldFeatureController showMessage( BuildContext context, @@ -14,3 +18,43 @@ ScaffoldFeatureController showMessage( width: narrow ? null : 400, )); } + +Future showBottomMenu( + BuildContext context, List actions) async { + await showModalBottomSheet( + context: context, + constraints: MediaQuery.of(context).size.width > 540 + ? const BoxConstraints(maxWidth: 380) + : null, + builder: (context) => _BottomMenu(actions), + ); +} + +class _BottomMenu extends ConsumerWidget { + final List actions; + const _BottomMenu(this.actions); + + @override + Widget build(BuildContext context, WidgetRef ref) { + // If current device changes, we need to pop back to the main Page. + ref.listen(currentDeviceProvider, (previous, next) { + Navigator.of(context).pop(); + }); + + return Column( + mainAxisSize: MainAxisSize.min, + children: actions + .map((a) => ListTile( + leading: a.icon, + title: Text(a.text), + onTap: a.action == null + ? null + : () { + Navigator.pop(context); + a.action?.call(context); + }, + )) + .toList(), + ); + } +} diff --git a/lib/app/models.dart b/lib/app/models.dart index eb73f334..01d58e48 100755 --- a/lib/app/models.dart +++ b/lib/app/models.dart @@ -93,6 +93,9 @@ class DevicePath { int get hashCode => Object.hashAll(segments); String get key => segments.join('/'); + + @override + String toString() => key; } @freezed diff --git a/lib/app/views/app_page.dart b/lib/app/views/app_page.dart index aede181a..fe69de95 100755 --- a/lib/app/views/app_page.dart +++ b/lib/app/views/app_page.dart @@ -9,13 +9,13 @@ class AppPage extends ConsumerWidget { final Widget? title; final Widget child; final Widget? floatingActionButton; - final void Function()? onBack; + final bool centered; AppPage( {Key? key, this.title, required this.child, - this.onBack, - this.floatingActionButton}) + this.floatingActionButton, + this.centered = false}) : super(key: key); @override @@ -45,21 +45,24 @@ class AppPage extends ConsumerWidget { }, ); + Widget _buildScrollView() => SingleChildScrollView( + // Make sure FAB doesn't block content + padding: floatingActionButton != null + ? const EdgeInsets.only(bottom: 72) + : null, + child: child, + ); + Scaffold _buildScaffold(BuildContext context, WidgetRef ref, bool hasDrawer) { return Scaffold( key: _scaffoldKey, appBar: AppBar( - leading: onBack != null - ? BackButton( - onPressed: onBack, - ) - : null, title: title, centerTitle: true, actions: const [DeviceButton()], ), drawer: hasDrawer ? const MainPageDrawer() : null, - body: child, + body: centered ? Center(child: _buildScrollView()) : _buildScrollView(), floatingActionButton: floatingActionButton, ); } diff --git a/lib/app/views/device_info_screen.dart b/lib/app/views/device_info_screen.dart index 03a6346b..5e5f2773 100755 --- a/lib/app/views/device_info_screen.dart +++ b/lib/app/views/device_info_screen.dart @@ -10,14 +10,9 @@ class DeviceInfoScreen extends StatelessWidget { @override Widget build(BuildContext context) { return AppPage( - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: const [ - Text('This page intentionally left blank (for now)'), - ], - ), - ), + title: const Text('Coming soon!'), + centered: true, + child: const Text('This page intentionally left blank (for now)'), ); } } diff --git a/lib/app/views/main_page.dart b/lib/app/views/main_page.dart index 7140a87e..a80bb8fd 100755 --- a/lib/app/views/main_page.dart +++ b/lib/app/views/main_page.dart @@ -28,7 +28,7 @@ class MainPage extends ConsumerWidget { switch (app) { case Application.oath: - return OathScreen(deviceData); + return OathScreen(deviceData.node.path); case Application.management: return ManagementScreen(deviceData); case Application.fido: diff --git a/lib/app/views/no_device_screen.dart b/lib/app/views/no_device_screen.dart index 783349cb..abb426a4 100755 --- a/lib/app/views/no_device_screen.dart +++ b/lib/app/views/no_device_screen.dart @@ -58,22 +58,21 @@ class NoDeviceScreen extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { return AppPage( - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: node?.map(usbYubiKey: (node) { - return _buildUsbPid(context, ref, node.pid); - }, nfcReader: (node) { - return const [ - DeviceAvatar(child: Icon(Icons.wifi)), - Text('Place your YubiKey on the NFC reader'), - ]; - }) ?? - const [ - DeviceAvatar(child: Icon(Icons.usb)), - Text('Insert your YubiKey'), - ], - ), + centered: true, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: node?.map(usbYubiKey: (node) { + return _buildUsbPid(context, ref, node.pid); + }, nfcReader: (node) { + return const [ + DeviceAvatar(child: Icon(Icons.wifi)), + Text('Place your YubiKey on the NFC reader'), + ]; + }) ?? + const [ + DeviceAvatar(child: Icon(Icons.usb)), + Text('Insert your YubiKey'), + ], ), ); }