diff --git a/lib/components/DangerButton.dart b/lib/components/DangerButton.dart new file mode 100644 index 0000000..4279c5e --- /dev/null +++ b/lib/components/DangerButton.dart @@ -0,0 +1,28 @@ +import 'dart:io'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class DangerButton extends StatelessWidget { + const DangerButton({Key? key, required this.child, this.onPressed}) : super(key: key); + + final Widget child; + final GestureTapCallback? onPressed; + + @override + Widget build(BuildContext context) { + if (Platform.isAndroid) { + return FilledButton( + onPressed: onPressed, + child: child, + style: FilledButton.styleFrom(backgroundColor: Theme.of(context).colorScheme.error)); + } else { + // Workaround for https://github.com/flutter/flutter/issues/161590 + final themeData = CupertinoTheme.of(context); + return CupertinoTheme( + data: themeData.copyWith(primaryColor: CupertinoColors.white), + child: CupertinoButton( + child: child, onPressed: onPressed, color: CupertinoColors.systemRed.resolveFrom(context))); + } + } +} diff --git a/lib/main.dart b/lib/main.dart index a81f1a6..ad222c6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,8 @@ import 'dart:async'; -import 'package:flutter/cupertino.dart' show CupertinoThemeData, DefaultCupertinoLocalizations; +import 'package:flutter/cupertino.dart' show CupertinoThemeData, DefaultCupertinoLocalizations, CupertinoColors; import 'package:flutter/material.dart' - show BottomSheetThemeData, Colors, DefaultMaterialLocalizations, ThemeData, ThemeMode; + show BottomSheetThemeData, ColorScheme, Colors, DefaultMaterialLocalizations, ThemeData, ThemeMode; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; @@ -87,8 +87,11 @@ class _AppState extends State { Widget build(BuildContext context) { final ThemeData lightTheme = ThemeData( useMaterial3: false, - brightness: Brightness.light, - primarySwatch: Colors.blueGrey, + colorScheme: ColorScheme.fromSwatch( + brightness: Brightness.light, + primarySwatch: Colors.blueGrey, + errorColor: CupertinoColors.systemRed.resolveFrom(context), + ), primaryColor: Colors.blueGrey[900], fontFamily: 'PublicSans', //scaffoldBackgroundColor: Colors.grey[100], @@ -100,8 +103,11 @@ class _AppState extends State { final ThemeData darkTheme = ThemeData( useMaterial3: false, - brightness: Brightness.dark, - primarySwatch: Colors.grey, + colorScheme: ColorScheme.fromSwatch( + brightness: Brightness.dark, + primarySwatch: Colors.grey, + errorColor: CupertinoColors.systemRed.resolveFrom(context), + ), primaryColor: Colors.grey[900], fontFamily: 'PublicSans', scaffoldBackgroundColor: Colors.grey[800], diff --git a/lib/screens/HostInfoScreen.dart b/lib/screens/HostInfoScreen.dart index 169a22c..1c850b8 100644 --- a/lib/screens/HostInfoScreen.dart +++ b/lib/screens/HostInfoScreen.dart @@ -1,6 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; +import 'package:mobile_nebula/components/DangerButton.dart'; import 'package:mobile_nebula/components/SimplePage.dart'; import 'package:mobile_nebula/components/config/ConfigCheckboxItem.dart'; import 'package:mobile_nebula/components/config/ConfigItem.dart'; @@ -161,9 +162,8 @@ class _HostInfoScreenState extends State { padding: EdgeInsets.only(top: 50, bottom: 10, left: 10, right: 10), child: SizedBox( width: double.infinity, - child: PlatformElevatedButton( + child: DangerButton( child: Text('Close Tunnel'), - color: CupertinoColors.systemRed.resolveFrom(context), onPressed: () => Utils.confirmDelete(context, 'Close Tunnel?', () async { try { await widget.site.closeTunnel(hostInfo.vpnIp); diff --git a/lib/screens/SiteDetailScreen.dart b/lib/screens/SiteDetailScreen.dart index 6bf2c19..07b1ba0 100644 --- a/lib/screens/SiteDetailScreen.dart +++ b/lib/screens/SiteDetailScreen.dart @@ -17,6 +17,8 @@ import 'package:mobile_nebula/screens/siteConfig/SiteConfigScreen.dart'; import 'package:mobile_nebula/services/utils.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; +import '../components/DangerButton.dart'; + //TODO: If the site isn't active, don't respond to reloads on hostmaps //TODO: ios is now the problem with connecting screwing our ability to query the hostmap (its a race) @@ -256,14 +258,14 @@ class _SiteDetailScreenState extends State { padding: EdgeInsets.only(top: 50, bottom: 10, left: 10, right: 10), child: SizedBox( width: double.infinity, - child: PlatformElevatedButton( - child: Text('Delete'), - color: CupertinoColors.systemRed.resolveFrom(context), - onPressed: () => Utils.confirmDelete(context, 'Delete Site?', () async { - if (await _deleteSite()) { - Navigator.of(context).pop(); - } - })))); + child: DangerButton( + child: Text('Delete'), + onPressed: () => Utils.confirmDelete(context, 'Delete Site?', () async { + if (await _deleteSite()) { + Navigator.of(context).pop(); + } + }), + ))); } _listHostmap() async { diff --git a/lib/screens/siteConfig/CertificateDetailsScreen.dart b/lib/screens/siteConfig/CertificateDetailsScreen.dart index f6fb76c..6b421a5 100644 --- a/lib/screens/siteConfig/CertificateDetailsScreen.dart +++ b/lib/screens/siteConfig/CertificateDetailsScreen.dart @@ -1,6 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; +import 'package:mobile_nebula/components/DangerButton.dart'; import 'package:mobile_nebula/components/FormPage.dart'; import 'package:mobile_nebula/components/config/ConfigItem.dart'; import 'package:mobile_nebula/components/config/ConfigSection.dart'; @@ -164,9 +165,8 @@ class _CertificateDetailsScreenState extends State { padding: EdgeInsets.only(top: 50, bottom: 10, left: 10, right: 10), child: SizedBox( width: double.infinity, - child: PlatformElevatedButton( + child: DangerButton( child: Text('Replace certificate'), - color: CupertinoColors.systemRed.resolveFrom(context), onPressed: () { Utils.openPage(context, (context) { return AddCertificateScreen( @@ -199,9 +199,8 @@ class _CertificateDetailsScreenState extends State { padding: EdgeInsets.only(top: 50, bottom: 10, left: 10, right: 10), child: SizedBox( width: double.infinity, - child: PlatformElevatedButton( + child: DangerButton( child: Text('Delete'), - color: CupertinoColors.systemRed.resolveFrom(context), onPressed: () => Utils.confirmDelete(context, title, () async { Navigator.pop(context); widget.onDelete!(); diff --git a/lib/screens/siteConfig/StaticHostmapScreen.dart b/lib/screens/siteConfig/StaticHostmapScreen.dart index f07e028..3f92209 100644 --- a/lib/screens/siteConfig/StaticHostmapScreen.dart +++ b/lib/screens/siteConfig/StaticHostmapScreen.dart @@ -1,6 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; +import 'package:mobile_nebula/components/DangerButton.dart'; import 'package:mobile_nebula/components/FormPage.dart'; import 'package:mobile_nebula/components/IPAndPortFormField.dart'; import 'package:mobile_nebula/components/IPFormField.dart'; @@ -119,14 +120,12 @@ class _StaticHostmapScreenState extends State { padding: EdgeInsets.only(top: 50, bottom: 10, left: 10, right: 10), child: SizedBox( width: double.infinity, - child: PlatformElevatedButton( - child: Text('Delete'), - color: CupertinoColors.systemRed.resolveFrom(context), - onPressed: () => Utils.confirmDelete(context, 'Delete host map?', () { - Navigator.of(context).pop(); - widget.onDelete!(); - }), - ))) + child: DangerButton( + child: Text('Delete'), + onPressed: () => Utils.confirmDelete(context, 'Delete host map?', () { + Navigator.of(context).pop(); + widget.onDelete!(); + })))) : Container() ])); } diff --git a/lib/screens/siteConfig/UnsafeRouteScreen.dart b/lib/screens/siteConfig/UnsafeRouteScreen.dart index a7d3771..ab168b0 100644 --- a/lib/screens/siteConfig/UnsafeRouteScreen.dart +++ b/lib/screens/siteConfig/UnsafeRouteScreen.dart @@ -1,6 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:mobile_nebula/components/CIDRFormField.dart'; +import 'package:mobile_nebula/components/DangerButton.dart'; import 'package:mobile_nebula/components/FormPage.dart'; import 'package:mobile_nebula/components/IPFormField.dart'; import 'package:mobile_nebula/components/config/ConfigItem.dart'; @@ -96,9 +97,8 @@ class _UnsafeRouteScreenState extends State { padding: EdgeInsets.only(top: 50, bottom: 10, left: 10, right: 10), child: SizedBox( width: double.infinity, - child: PlatformElevatedButton( + child: DangerButton( child: Text('Delete'), - color: CupertinoColors.systemRed.resolveFrom(context), onPressed: () => Utils.confirmDelete(context, 'Delete unsafe route?', () { Navigator.of(context).pop(); widget.onDelete!();