yubioath-flutter/lib/app/views/main_drawer.dart

231 lines
7.2 KiB
Dart
Raw Normal View History

2022-10-04 13:12:54 +03:00
/*
* Copyright (C) 2022 Yubico.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import 'dart:io';
2021-11-24 10:44:28 +03:00
import 'package:flutter/material.dart';
2022-07-27 13:00:31 +03:00
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
2021-11-24 10:44:28 +03:00
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../about_page.dart';
import '../../android/views/android_settings_page.dart';
import '../../management/views/management_screen.dart';
import '../../settings_page.dart';
2022-07-04 13:56:31 +03:00
import '../message.dart';
2021-11-24 10:44:28 +03:00
import '../models.dart';
import '../state.dart';
2022-10-03 16:34:06 +03:00
import 'keys.dart';
2021-11-24 10:44:28 +03:00
extension on Application {
IconData get _icon {
switch (this) {
case Application.oath:
return Icons.supervisor_account;
case Application.fido:
return Icons.security;
case Application.otp:
return Icons.password;
case Application.piv:
return Icons.approval;
case Application.management:
return Icons.construction;
case Application.openpgp:
return Icons.key;
case Application.hsmauth:
return Icons.key;
}
}
}
2021-11-24 10:44:28 +03:00
class MainPageDrawer extends ConsumerWidget {
2022-03-03 19:09:03 +03:00
final bool shouldPop;
2022-05-12 10:56:55 +03:00
const MainPageDrawer({this.shouldPop = true, super.key});
2021-11-24 10:44:28 +03:00
@override
Widget build(BuildContext context, WidgetRef ref) {
final supportedApps = ref.watch(supportedAppsProvider);
final data =
ref.watch(currentDeviceDataProvider).whenOrNull(data: (data) => data);
final currentApp = ref.watch(currentAppProvider);
2022-05-20 15:16:50 +03:00
MediaQuery? mediaQuery =
context.findAncestorWidgetOfExactType<MediaQuery>();
final width = mediaQuery?.data.size.width ?? 400;
2022-08-12 10:53:34 +03:00
final color =
Theme.of(context).brightness == Brightness.dark ? 'white' : 'green';
2022-05-20 15:16:50 +03:00
return Drawer(
width: width < 357 ? 0.85 * width : null,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topRight: Radius.circular(20.0),
bottomRight: Radius.circular(20.0))),
child: ListView(
primary: false, //Prevents conflict with the MainPage scroll view.
children: [
2022-08-12 10:53:34 +03:00
Padding(
padding: const EdgeInsets.only(top: 19.0, left: 30.0, bottom: 12.0),
child: Image.asset(
'assets/graphics/yubico-$color.png',
alignment: Alignment.centerLeft,
height: 28,
filterQuality: FilterQuality.medium,
),
),
const Divider(indent: 16.0, endIndent: 28.0),
2022-05-20 15:16:50 +03:00
if (data != null) ...[
// Normal YubiKey Applications
...supportedApps
.where((app) =>
app != Application.management &&
app.getAvailability(data) != Availability.unsupported)
.map((app) => ApplicationItem(
app: app,
available:
app.getAvailability(data) == Availability.enabled,
selected: app == currentApp,
onSelect: () {
if (shouldPop) Navigator.of(context).pop();
},
)),
// Management app
if (supportedApps.contains(Application.management) &&
Application.management.getAvailability(data) ==
Availability.enabled) ...[
DrawerItem(
2022-07-27 13:00:31 +03:00
titleText:
AppLocalizations.of(context)!.mainDrawer_txt_applications,
2022-05-20 15:16:50 +03:00
icon: Icon(Application.management._icon),
2022-10-03 16:34:06 +03:00
key: managementAppDrawer,
2022-05-20 15:16:50 +03:00
onTap: () {
if (shouldPop) Navigator.of(context).pop();
2022-07-04 13:56:31 +03:00
showBlurDialog(
2022-05-18 12:52:50 +03:00
context: context,
2022-10-03 16:39:57 +03:00
builder: (context) => ManagementScreen(data),
2022-05-20 15:16:50 +03:00
);
},
),
],
const Divider(indent: 16.0, endIndent: 28.0),
2022-05-18 12:52:50 +03:00
],
2022-05-20 15:16:50 +03:00
// Non-YubiKey pages
DrawerItem(
2022-07-27 13:00:31 +03:00
titleText: AppLocalizations.of(context)!.mainDrawer_txt_settings,
2022-05-20 15:16:50 +03:00
icon: const Icon(Icons.settings),
onTap: () {
final nav = Navigator.of(context);
if (shouldPop) nav.pop();
2022-07-04 13:56:31 +03:00
showBlurDialog(
context: context,
builder: (context) => Platform.isAndroid
? const AndroidSettingsPage()
: const SettingsPage(),
routeSettings: const RouteSettings(name: 'settings'),
);
2022-05-20 15:16:50 +03:00
},
),
DrawerItem(
2022-07-27 13:00:31 +03:00
titleText: AppLocalizations.of(context)!.mainDrawer_txt_help,
2022-05-20 15:16:50 +03:00
icon: const Icon(Icons.help),
onTap: () {
final nav = Navigator.of(context);
if (shouldPop) nav.pop();
2022-07-04 13:56:31 +03:00
showBlurDialog(
context: context,
builder: (context) => const AboutPage(),
routeSettings: const RouteSettings(name: 'about'),
);
2022-05-20 15:16:50 +03:00
},
),
],
2021-11-24 10:44:28 +03:00
),
);
}
}
class ApplicationItem extends ConsumerWidget {
final Application app;
final bool available;
final bool selected;
final Function onSelect;
const ApplicationItem({
required this.app,
required this.available,
required this.selected,
required this.onSelect,
2022-05-12 10:56:55 +03:00
super.key,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
return DrawerItem(
titleText: app.displayName,
icon: Icon(app._icon),
selected: selected,
enabled: available,
onTap: available & !selected
? () {
ref.read(currentAppProvider.notifier).setCurrentApp(app);
onSelect();
}
: null,
);
}
}
class DrawerItem extends StatelessWidget {
final bool enabled;
final bool selected;
final String titleText;
final Icon icon;
final void Function()? onTap;
const DrawerItem({
required this.titleText,
required this.icon,
this.onTap,
this.selected = false,
this.enabled = true,
2022-05-12 10:56:55 +03:00
super.key,
});
@override
Widget build(BuildContext context) {
return Padding(
2022-05-18 12:52:50 +03:00
padding: const EdgeInsets.only(left: 12.0, right: 12.0),
child: ListTile(
enabled: enabled,
shape: const RoundedRectangleBorder(
2022-05-18 12:52:50 +03:00
borderRadius: BorderRadius.all(Radius.circular(30)),
),
dense: true,
2022-05-18 12:52:50 +03:00
minLeadingWidth: 24,
minVerticalPadding: 18,
selected: selected,
2022-05-20 15:10:17 +03:00
selectedColor: Theme.of(context).colorScheme.onPrimary,
selectedTileColor: Theme.of(context).colorScheme.primary,
2022-05-20 12:10:49 +03:00
leading: IconTheme.merge(
data: const IconThemeData(size: 24),
child: icon,
),
2021-12-02 22:29:40 +03:00
title: Text(titleText),
onTap: onTap,
),
);
}
}