From bae11143b06f949565f58df8ae65754ff48668b1 Mon Sep 17 00:00:00 2001 From: Nikolas Rimikis Date: Tue, 11 Jul 2023 12:48:44 +0200 Subject: [PATCH] neon: rework DialogTheme --- packages/neon/neon/lib/src/pages/login.dart | 2 +- .../lib/src/pages/login_check_account.dart | 2 +- .../src/pages/login_check_server_status.dart | 2 +- packages/neon/neon/lib/src/utils/theme.dart | 84 ++++++++++++++++--- 4 files changed, 77 insertions(+), 13 deletions(-) diff --git a/packages/neon/neon/lib/src/pages/login.dart b/packages/neon/neon/lib/src/pages/login.dart index 64e57783..b8629315 100644 --- a/packages/neon/neon/lib/src/pages/login.dart +++ b/packages/neon/neon/lib/src/pages/login.dart @@ -60,7 +60,7 @@ class _LoginPageState extends State { ), body: Center( child: ConstrainedBox( - constraints: Theme.of(context).extension()?.tabletLayout ?? const BoxConstraints(), + constraints: NeonDialogTheme.of(context).constraints, child: Scrollbar( interactive: true, child: SingleChildScrollView( diff --git a/packages/neon/neon/lib/src/pages/login_check_account.dart b/packages/neon/neon/lib/src/pages/login_check_account.dart index 37d1d9aa..6c296f0f 100644 --- a/packages/neon/neon/lib/src/pages/login_check_account.dart +++ b/packages/neon/neon/lib/src/pages/login_check_account.dart @@ -56,7 +56,7 @@ class _LoginCheckAccountPageState extends State { child: Padding( padding: const EdgeInsets.all(10), child: ConstrainedBox( - constraints: Theme.of(context).extension()?.tabletLayout ?? const BoxConstraints(), + constraints: NeonDialogTheme.of(context).constraints, child: ResultBuilder.behaviorSubject( stream: bloc.state, builder: (final context, final state) => Column( diff --git a/packages/neon/neon/lib/src/pages/login_check_server_status.dart b/packages/neon/neon/lib/src/pages/login_check_server_status.dart index 622b67f7..785c5e33 100644 --- a/packages/neon/neon/lib/src/pages/login_check_server_status.dart +++ b/packages/neon/neon/lib/src/pages/login_check_server_status.dart @@ -44,7 +44,7 @@ class _LoginCheckServerStatusPageState extends State child: Padding( padding: const EdgeInsets.all(10), child: ConstrainedBox( - constraints: Theme.of(context).extension()?.tabletLayout ?? const BoxConstraints(), + constraints: NeonDialogTheme.of(context).constraints, child: ResultBuilder.behaviorSubject( stream: bloc.state, builder: (final context, final state) => Column( diff --git a/packages/neon/neon/lib/src/utils/theme.dart b/packages/neon/neon/lib/src/utils/theme.dart index c72c0682..aa76cc9c 100644 --- a/packages/neon/neon/lib/src/utils/theme.dart +++ b/packages/neon/neon/lib/src/utils/theme.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:meta/meta.dart'; import 'package:neon/src/utils/hex_color.dart'; +import 'package:neon/src/widgets/dialog.dart'; import 'package:nextcloud/nextcloud.dart'; @internal @@ -48,11 +49,7 @@ class AppTheme { snackBarTheme: _snackBarTheme, dividerTheme: _dividerTheme, extensions: [ - const NeonTheme( - tabletLayout: BoxConstraints( - maxWidth: 640, - ), - ), + const NeonTheme(), ...?appThemes, ], ); @@ -71,21 +68,27 @@ class AppTheme { ); } +/// Defines the configuration of the overall visual [Theme] for a NeonApp +/// or a widget subtree within the app. @internal @immutable class NeonTheme extends ThemeExtension { + /// Create a [NeonTheme] that's used to configure a [Theme]. const NeonTheme({ - required this.tabletLayout, + this.dialogTheme = const NeonDialogTheme(), }); - final BoxConstraints? tabletLayout; + /// A theme for customizing the visual properties of [NeonDialog]s. + /// + /// This is the value returned from [NeonDialogTheme.of]. + final NeonDialogTheme dialogTheme; @override NeonTheme copyWith({ - final BoxConstraints? tabletLayout, + final NeonDialogTheme? dialogTheme, }) => NeonTheme( - tabletLayout: tabletLayout ?? this.tabletLayout, + dialogTheme: dialogTheme ?? this.dialogTheme, ); @override @@ -94,7 +97,68 @@ class NeonTheme extends ThemeExtension { return this; } return NeonTheme( - tabletLayout: BoxConstraints.lerp(tabletLayout, other.tabletLayout, t), + dialogTheme: NeonDialogTheme.lerp(dialogTheme, other.dialogTheme, t), ); } } + +/// Defines a theme for [NeonDialog] widgets. +/// +/// Descendant widgets obtain the current [NeonDialogTheme] object using +/// `NeonDialogTheme.of(context)`. Instances of [NeonDialogTheme] can be customized with +/// [NeonDialogTheme.copyWith]. +@immutable +class NeonDialogTheme { + /// Creates a dialog theme that can be used for [NeonTheme.dialogTheme]. + const NeonDialogTheme({ + this.constraints = const BoxConstraints( + minWidth: 280, + maxWidth: 560, + ), + }); + + /// Used to configure the [BoxConstraints] for the [NeonDialog] widget. + /// + /// This value should also be used on [Dialog.fullscreen] and other similar pages. + /// By default it follows the default [m3 dialog specification](https://m3.material.io/components/dialogs/specs). + final BoxConstraints constraints; + + /// Creates a copy of this object but with the given fields replaced with the + /// new values. + NeonDialogTheme copyWith({ + final BoxConstraints? constraints, + }) => + NeonDialogTheme( + constraints: constraints ?? this.constraints, + ); + + /// The data from the closest [NeonDialogTheme] instance given the build context. + static NeonDialogTheme of(final BuildContext context) => Theme.of(context).extension()!.dialogTheme; + + /// Linearly interpolate between two neon dialog themes. + /// + /// {@macro dart.ui.shadow.lerp} + // ignore: prefer_constructors_over_static_methods + static NeonDialogTheme lerp(final NeonDialogTheme a, final NeonDialogTheme b, final double t) { + if (identical(a, b)) { + return a; + } + return NeonDialogTheme( + constraints: BoxConstraints.lerp(a.constraints, b.constraints, t)!, + ); + } + + @override + int get hashCode => constraints.hashCode; + + @override + bool operator ==(final Object other) { + if (identical(this, other)) { + return true; + } + if (other.runtimeType != runtimeType) { + return false; + } + return other is NeonDialogTheme && other.constraints == constraints; + } +}