Browse Source

neon: constrain settings pages

pull/456/head
Nikolas Rimikis 1 year ago
parent
commit
18f062a614
No known key found for this signature in database
GPG Key ID: 85ED1DE9786A4FF2
  1. 190
      packages/neon/neon/lib/src/pages/account_settings.dart
  2. 98
      packages/neon/neon/lib/src/pages/nextcloud_app_settings.dart
  3. 457
      packages/neon/neon/lib/src/pages/settings.dart

190
packages/neon/neon/lib/src/pages/account_settings.dart

@ -10,13 +10,14 @@ import 'package:neon/src/settings/widgets/custom_settings_tile.dart';
import 'package:neon/src/settings/widgets/dropdown_button_settings_tile.dart';
import 'package:neon/src/settings/widgets/settings_category.dart';
import 'package:neon/src/settings/widgets/settings_list.dart';
import 'package:neon/src/theme/dialog.dart';
import 'package:neon/src/utils/confirmation_dialog.dart';
import 'package:neon/src/widgets/exception.dart';
import 'package:neon/src/widgets/linear_progress_indicator.dart';
import 'package:nextcloud/nextcloud.dart';
class AccountSettingsPage extends StatelessWidget {
AccountSettingsPage({
const AccountSettingsPage({
required this.bloc,
required this.account,
super.key,
@ -25,104 +26,115 @@ class AccountSettingsPage extends StatelessWidget {
final AccountsBloc bloc;
final Account account;
late final _options = bloc.getOptionsFor(account);
late final _userDetailsBloc = bloc.getUserDetailsBlocFor(account);
late final _name = account.client.humanReadableID;
@override
Widget build(final BuildContext context) => Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: Text(_name),
actions: [
IconButton(
onPressed: () async {
if (await showConfirmationDialog(
context,
AppLocalizations.of(context).accountOptionsRemoveConfirm(account.client.humanReadableID),
)) {
final isActive = bloc.activeAccount.value == account;
Widget build(final BuildContext context) {
final options = bloc.getOptionsFor(account);
final userDetailsBloc = bloc.getUserDetailsBlocFor(account);
final name = account.client.humanReadableID;
final appBar = AppBar(
title: Text(name),
actions: [
IconButton(
onPressed: () async {
if (await showConfirmationDialog(
context,
AppLocalizations.of(context).accountOptionsRemoveConfirm(account.client.humanReadableID),
)) {
final isActive = bloc.activeAccount.value == account;
bloc.removeAccount(account);
bloc.removeAccount(account);
// ignore: use_build_context_synchronously
if (!context.mounted) {
return;
}
// ignore: use_build_context_synchronously
if (!context.mounted) {
return;
}
if (isActive) {
const HomeRoute().go(context);
} else {
Navigator.of(context).pop();
}
}
},
tooltip: AppLocalizations.of(context).accountOptionsRemove,
icon: Icon(MdiIcons.delete),
),
IconButton(
onPressed: () async {
if (await showConfirmationDialog(
context,
AppLocalizations.of(context).settingsResetForConfirmation(_name),
)) {
await _options.reset();
}
},
tooltip: AppLocalizations.of(context).settingsResetFor(_name),
icon: Icon(MdiIcons.cogRefresh),
),
],
if (isActive) {
const HomeRoute().go(context);
} else {
Navigator.of(context).pop();
}
}
},
tooltip: AppLocalizations.of(context).accountOptionsRemove,
icon: Icon(MdiIcons.delete),
),
body: ResultBuilder<ProvisioningApiUserDetails>.behaviorSubject(
stream: _userDetailsBloc.userDetails,
builder: (final context, final userDetails) => SettingsList(
categories: [
SettingsCategory(
title: Text(AppLocalizations.of(context).accountOptionsCategoryStorageInfo),
tiles: [
CustomSettingsTile(
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (userDetails.hasData) ...[
LinearProgressIndicator(
value: userDetails.requireData.quota.relative / 100,
backgroundColor: Theme.of(context).colorScheme.primary.withOpacity(0.3),
),
const SizedBox(
height: 10,
),
Text(
AppLocalizations.of(context).accountOptionsQuotaUsedOf(
filesize(userDetails.requireData.quota.used, 1),
filesize(userDetails.requireData.quota.total, 1),
userDetails.requireData.quota.relative.toString(),
),
),
],
NeonException(
userDetails.error,
onRetry: _userDetailsBloc.refresh,
),
NeonLinearProgressIndicator(
visible: userDetails.isLoading,
IconButton(
onPressed: () async {
if (await showConfirmationDialog(
context,
AppLocalizations.of(context).settingsResetForConfirmation(name),
)) {
await options.reset();
}
},
tooltip: AppLocalizations.of(context).settingsResetFor(name),
icon: Icon(MdiIcons.cogRefresh),
),
],
);
final body = ResultBuilder<ProvisioningApiUserDetails>.behaviorSubject(
stream: userDetailsBloc.userDetails,
builder: (final context, final userDetails) => SettingsList(
categories: [
SettingsCategory(
title: Text(AppLocalizations.of(context).accountOptionsCategoryStorageInfo),
tiles: [
CustomSettingsTile(
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (userDetails.hasData) ...[
LinearProgressIndicator(
value: userDetails.requireData.quota.relative / 100,
backgroundColor: Theme.of(context).colorScheme.primary.withOpacity(0.3),
),
const SizedBox(
height: 10,
),
Text(
AppLocalizations.of(context).accountOptionsQuotaUsedOf(
filesize(userDetails.requireData.quota.used, 1),
filesize(userDetails.requireData.quota.total, 1),
userDetails.requireData.quota.relative.toString(),
),
],
),
],
NeonException(
userDetails.error,
onRetry: userDetailsBloc.refresh,
),
),
],
NeonLinearProgressIndicator(
visible: userDetails.isLoading,
),
],
),
),
SettingsCategory(
title: Text(AppLocalizations.of(context).optionsCategoryGeneral),
tiles: [
DropdownButtonSettingsTile(
option: _options.initialApp,
),
],
],
),
SettingsCategory(
title: Text(AppLocalizations.of(context).optionsCategoryGeneral),
tiles: [
DropdownButtonSettingsTile(
option: options.initialApp,
),
],
),
],
),
);
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: appBar,
body: Center(
child: ConstrainedBox(
constraints: NeonDialogTheme.of(context).constraints,
child: body,
),
);
),
);
}
}

98
packages/neon/neon/lib/src/pages/nextcloud_app_settings.dart

@ -8,6 +8,7 @@ import 'package:neon/src/settings/widgets/checkbox_settings_tile.dart';
import 'package:neon/src/settings/widgets/dropdown_button_settings_tile.dart';
import 'package:neon/src/settings/widgets/settings_category.dart';
import 'package:neon/src/settings/widgets/settings_list.dart';
import 'package:neon/src/theme/dialog.dart';
import 'package:neon/src/utils/confirmation_dialog.dart';
class NextcloudAppSettingsPage extends StatelessWidget {
@ -19,53 +20,62 @@ class NextcloudAppSettingsPage extends StatelessWidget {
final AppImplementation appImplementation;
@override
Widget build(final BuildContext context) => Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: Text(appImplementation.name(context)),
actions: [
IconButton(
onPressed: () async {
if (await showConfirmationDialog(
context,
AppLocalizations.of(context).settingsResetForConfirmation(appImplementation.name(context)),
)) {
await appImplementation.options.reset();
}
},
tooltip: AppLocalizations.of(context).settingsResetFor(appImplementation.name(context)),
icon: Icon(MdiIcons.cogRefresh),
),
],
Widget build(final BuildContext context) {
final appBar = AppBar(
title: Text(appImplementation.name(context)),
actions: [
IconButton(
onPressed: () async {
if (await showConfirmationDialog(
context,
AppLocalizations.of(context).settingsResetForConfirmation(appImplementation.name(context)),
)) {
await appImplementation.options.reset();
}
},
tooltip: AppLocalizations.of(context).settingsResetFor(appImplementation.name(context)),
icon: Icon(MdiIcons.cogRefresh),
),
body: SettingsList(
categories: [
for (final category in [...appImplementation.options.categories, null]) ...[
if (appImplementation.options.options
.where((final option) => option.category == category)
.isNotEmpty) ...[
SettingsCategory(
title: Text(
category != null ? category.name(context) : AppLocalizations.of(context).optionsCategoryOther,
),
tiles: [
for (final option
in appImplementation.options.options.where((final option) => option.category == category)) ...[
if (option is ToggleOption) ...[
CheckBoxSettingsTile(
option: option,
),
] else if (option is SelectOption) ...[
DropdownButtonSettingsTile(
option: option,
),
],
],
],
);
final body = SettingsList(
categories: [
for (final category in [...appImplementation.options.categories, null]) ...[
if (appImplementation.options.options.where((final option) => option.category == category).isNotEmpty) ...[
SettingsCategory(
title: Text(
category != null ? category.name(context) : AppLocalizations.of(context).optionsCategoryOther,
),
tiles: [
for (final option
in appImplementation.options.options.where((final option) => option.category == category)) ...[
if (option is ToggleOption) ...[
CheckBoxSettingsTile(
option: option,
),
] else if (option is SelectOption) ...[
DropdownButtonSettingsTile(
option: option,
),
],
),
],
],
],
),
],
],
],
);
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: appBar,
body: Center(
child: ConstrainedBox(
constraints: NeonDialogTheme.of(context).constraints,
child: body,
),
);
),
);
}
}

457
packages/neon/neon/lib/src/pages/settings.dart

@ -19,6 +19,7 @@ import 'package:neon/src/settings/widgets/settings_list.dart';
import 'package:neon/src/settings/widgets/settings_tile.dart';
import 'package:neon/src/settings/widgets/text_settings_tile.dart';
import 'package:neon/src/theme/branding.dart';
import 'package:neon/src/theme/dialog.dart';
import 'package:neon/src/utils/confirmation_dialog.dart';
import 'package:neon/src/utils/global_options.dart';
import 'package:neon/src/utils/save_file.dart';
@ -57,263 +58,271 @@ class _SettingsPageState extends State<SettingsPage> {
final accountsBloc = Provider.of<AccountsBloc>(context, listen: false);
final appImplementations = Provider.of<Iterable<AppImplementation>>(context);
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: Text(AppLocalizations.of(context).settings),
actions: [
IconButton(
onPressed: () async {
if (await showConfirmationDialog(context, AppLocalizations.of(context).settingsResetAllConfirmation)) {
await globalOptions.reset();
final appBar = AppBar(
title: Text(AppLocalizations.of(context).settings),
actions: [
IconButton(
onPressed: () async {
if (await showConfirmationDialog(context, AppLocalizations.of(context).settingsResetAllConfirmation)) {
await globalOptions.reset();
for (final appImplementation in appImplementations) {
await appImplementation.options.reset();
}
for (final appImplementation in appImplementations) {
await appImplementation.options.reset();
}
for (final account in accountsBloc.accounts.value) {
await accountsBloc.getOptionsFor(account).reset();
}
for (final account in accountsBloc.accounts.value) {
await accountsBloc.getOptionsFor(account).reset();
}
},
tooltip: AppLocalizations.of(context).settingsResetAll,
icon: Icon(MdiIcons.cogRefresh),
),
],
),
body: StreamBuilder<List<Account>>(
stream: accountsBloc.accounts,
initialData: accountsBloc.accounts.valueOrNull,
builder: (
final context,
final accountsSnapshot,
) {
final platform = Provider.of<NeonPlatform>(context, listen: false);
return StreamBuilder<bool>(
stream: globalOptions.pushNotificationsEnabled.enabled,
initialData: globalOptions.pushNotificationsEnabled.enabled.valueOrNull,
builder: (
final context,
final pushNotificationsEnabledEnabledSnapshot,
) =>
SettingsList(
initialCategory: widget.initialCategory?.name,
categories: [
}
},
tooltip: AppLocalizations.of(context).settingsResetAll,
icon: Icon(MdiIcons.cogRefresh),
),
],
);
final body = StreamBuilder<List<Account>>(
stream: accountsBloc.accounts,
initialData: accountsBloc.accounts.valueOrNull,
builder: (
final context,
final accountsSnapshot,
) {
final platform = Provider.of<NeonPlatform>(context, listen: false);
return StreamBuilder<bool>(
stream: globalOptions.pushNotificationsEnabled.enabled,
initialData: globalOptions.pushNotificationsEnabled.enabled.valueOrNull,
builder: (
final context,
final pushNotificationsEnabledEnabledSnapshot,
) =>
SettingsList(
initialCategory: widget.initialCategory?.name,
categories: [
SettingsCategory(
title: Text(AppLocalizations.of(context).settingsApps),
key: ValueKey(SettingsCageories.apps.name),
tiles: <SettingsTile>[
for (final appImplementation in appImplementations) ...[
if (appImplementation.options.options.isNotEmpty) ...[
CustomSettingsTile(
leading: appImplementation.buildIcon(),
title: Text(appImplementation.name(context)),
onTap: () {
NextcloudAppSettingsRoute(appid: appImplementation.id).go(context);
},
),
],
],
],
),
SettingsCategory(
title: Text(AppLocalizations.of(context).optionsCategoryTheme),
key: ValueKey(SettingsCageories.theme.name),
tiles: [
DropdownButtonSettingsTile(
option: globalOptions.themeMode,
),
CheckBoxSettingsTile(
option: globalOptions.themeOLEDAsDark,
),
CheckBoxSettingsTile(
option: globalOptions.themeKeepOriginalAccentColor,
),
],
),
SettingsCategory(
title: Text(AppLocalizations.of(context).optionsCategoryNavigation),
key: ValueKey(SettingsCageories.navigation.name),
tiles: [
DropdownButtonSettingsTile(
option: globalOptions.navigationMode,
),
],
),
if (platform.canUsePushNotifications) ...[
SettingsCategory(
title: Text(AppLocalizations.of(context).settingsApps),
key: ValueKey(SettingsCageories.apps.name),
tiles: <SettingsTile>[
for (final appImplementation in appImplementations) ...[
if (appImplementation.options.options.isNotEmpty) ...[
CustomSettingsTile(
leading: appImplementation.buildIcon(),
title: Text(appImplementation.name(context)),
onTap: () {
NextcloudAppSettingsRoute(appid: appImplementation.id).go(context);
},
title: Text(AppLocalizations.of(context).optionsCategoryPushNotifications),
key: ValueKey(SettingsCageories.pushNotifications.name),
tiles: [
if (pushNotificationsEnabledEnabledSnapshot.hasData &&
!pushNotificationsEnabledEnabledSnapshot.requireData) ...[
TextSettingsTile(
text: AppLocalizations.of(context).globalOptionsPushNotificationsEnabledDisabledNotice,
style: TextStyle(
fontWeight: FontWeight.w600,
fontStyle: FontStyle.italic,
color: Theme.of(context).colorScheme.error,
),
],
),
],
CheckBoxSettingsTile(
option: globalOptions.pushNotificationsEnabled,
),
DropdownButtonSettingsTile(
option: globalOptions.pushNotificationsDistributor,
),
],
),
],
if (platform.canUseWindowManager) ...[
SettingsCategory(
title: Text(AppLocalizations.of(context).optionsCategoryTheme),
key: ValueKey(SettingsCageories.theme.name),
title: Text(AppLocalizations.of(context).optionsCategoryStartup),
key: ValueKey(SettingsCageories.startup.name),
tiles: [
DropdownButtonSettingsTile(
option: globalOptions.themeMode,
),
CheckBoxSettingsTile(
option: globalOptions.themeOLEDAsDark,
option: globalOptions.startupMinimized,
),
CheckBoxSettingsTile(
option: globalOptions.themeKeepOriginalAccentColor,
option: globalOptions.startupMinimizeInsteadOfExit,
),
],
),
],
if (platform.canUseWindowManager && platform.canUseSystemTray) ...[
SettingsCategory(
title: Text(AppLocalizations.of(context).optionsCategoryNavigation),
key: ValueKey(SettingsCageories.navigation.name),
title: Text(AppLocalizations.of(context).optionsCategorySystemTray),
key: ValueKey(SettingsCageories.systemTray.name),
tiles: [
DropdownButtonSettingsTile(
option: globalOptions.navigationMode,
CheckBoxSettingsTile(
option: globalOptions.systemTrayEnabled,
),
CheckBoxSettingsTile(
option: globalOptions.systemTrayHideToTrayWhenMinimized,
),
],
),
if (platform.canUsePushNotifications) ...[
SettingsCategory(
title: Text(AppLocalizations.of(context).optionsCategoryPushNotifications),
key: ValueKey(SettingsCageories.pushNotifications.name),
tiles: [
if (pushNotificationsEnabledEnabledSnapshot.hasData &&
!pushNotificationsEnabledEnabledSnapshot.requireData) ...[
TextSettingsTile(
text: AppLocalizations.of(context).globalOptionsPushNotificationsEnabledDisabledNotice,
style: TextStyle(
fontWeight: FontWeight.w600,
fontStyle: FontStyle.italic,
color: Theme.of(context).colorScheme.error,
),
),
],
CheckBoxSettingsTile(
option: globalOptions.pushNotificationsEnabled,
),
DropdownButtonSettingsTile(
option: globalOptions.pushNotificationsDistributor,
),
],
),
],
if (platform.canUseWindowManager) ...[
SettingsCategory(
title: Text(AppLocalizations.of(context).optionsCategoryStartup),
key: ValueKey(SettingsCageories.startup.name),
tiles: [
CheckBoxSettingsTile(
option: globalOptions.startupMinimized,
),
CheckBoxSettingsTile(
option: globalOptions.startupMinimizeInsteadOfExit,
),
],
),
],
if (platform.canUseWindowManager && platform.canUseSystemTray) ...[
SettingsCategory(
title: Text(AppLocalizations.of(context).optionsCategorySystemTray),
key: ValueKey(SettingsCageories.systemTray.name),
tiles: [
CheckBoxSettingsTile(
option: globalOptions.systemTrayEnabled,
),
CheckBoxSettingsTile(
option: globalOptions.systemTrayHideToTrayWhenMinimized,
),
],
),
],
SettingsCategory(
title: Text(AppLocalizations.of(context).optionsCategoryAccounts),
key: ValueKey(SettingsCageories.accounts.name),
tiles: [
if (accountsSnapshot.requireData.length > 1) ...[
CheckBoxSettingsTile(
option: globalOptions.rememberLastUsedAccount,
),
DropdownButtonSettingsTile(
option: globalOptions.initialAccount,
),
],
for (final account in accountsSnapshot.requireData) ...[
AccountSettingsTile(
account: account,
onTap: () {
AccountSettingsRoute(accountid: account.id).go(context);
},
),
],
CustomSettingsTile(
title: ElevatedButton.icon(
onPressed: () async => const LoginRoute().push(context),
icon: Icon(MdiIcons.accountPlus),
label: Text(AppLocalizations.of(context).globalOptionsAccountsAdd),
),
)
],
SettingsCategory(
title: Text(AppLocalizations.of(context).optionsCategoryAccounts),
key: ValueKey(SettingsCageories.accounts.name),
tiles: [
if (accountsSnapshot.requireData.length > 1) ...[
CheckBoxSettingsTile(
option: globalOptions.rememberLastUsedAccount,
),
DropdownButtonSettingsTile(
option: globalOptions.initialAccount,
),
],
),
SettingsCategory(
title: Text(AppLocalizations.of(context).optionsCategoryOther),
key: ValueKey(SettingsCageories.other.name),
tiles: <SettingsTile>[
CustomSettingsTile(
leading: Icon(
MdiIcons.scriptText,
color: Theme.of(context).colorScheme.primary,
),
title: Text(AppLocalizations.of(context).licenses),
onTap: () async {
final branding = Branding.of(context);
showLicensePage(
context: context,
applicationName: branding.name,
applicationIcon: branding.logo,
applicationLegalese: branding.legalese,
applicationVersion: Provider.of<PackageInfo>(context, listen: false).version,
);
for (final account in accountsSnapshot.requireData) ...[
AccountSettingsTile(
account: account,
onTap: () {
AccountSettingsRoute(accountid: account.id).go(context);
},
),
CustomSettingsTile(
leading: Icon(
MdiIcons.export,
color: Theme.of(context).colorScheme.primary,
),
title: Text(AppLocalizations.of(context).settingsExport),
onTap: () async {
final settingsExportHelper = _buildSettingsExportHelper(context);
],
CustomSettingsTile(
title: ElevatedButton.icon(
onPressed: () async => const LoginRoute().push(context),
icon: Icon(MdiIcons.accountPlus),
label: Text(AppLocalizations.of(context).globalOptionsAccountsAdd),
),
)
],
),
SettingsCategory(
title: Text(AppLocalizations.of(context).optionsCategoryOther),
key: ValueKey(SettingsCageories.other.name),
tiles: <SettingsTile>[
CustomSettingsTile(
leading: Icon(
MdiIcons.scriptText,
color: Theme.of(context).colorScheme.primary,
),
title: Text(AppLocalizations.of(context).licenses),
onTap: () async {
final branding = Branding.of(context);
showLicensePage(
context: context,
applicationName: branding.name,
applicationIcon: branding.logo,
applicationLegalese: branding.legalese,
applicationVersion: Provider.of<PackageInfo>(context, listen: false).version,
);
},
),
CustomSettingsTile(
leading: Icon(
MdiIcons.export,
color: Theme.of(context).colorScheme.primary,
),
title: Text(AppLocalizations.of(context).settingsExport),
onTap: () async {
final settingsExportHelper = _buildSettingsExportHelper(context);
try {
final fileName =
'nextcloud-neon-settings-${DateTime.now().millisecondsSinceEpoch ~/ 1000}.json.base64';
final data = base64.encode(
utf8.encode(
json.encode(
settingsExportHelper.toJsonExport(),
),
try {
final fileName =
'nextcloud-neon-settings-${DateTime.now().millisecondsSinceEpoch ~/ 1000}.json.base64';
final data = base64.encode(
utf8.encode(
json.encode(
settingsExportHelper.toJsonExport(),
),
);
await saveFileWithPickDialog(fileName, Uint8List.fromList(utf8.encode(data)));
} catch (e, s) {
debugPrint(e.toString());
debugPrint(s.toString());
NeonException.showSnackbar(context, e);
}
},
),
);
await saveFileWithPickDialog(fileName, Uint8List.fromList(utf8.encode(data)));
} catch (e, s) {
debugPrint(e.toString());
debugPrint(s.toString());
NeonException.showSnackbar(context, e);
}
},
),
CustomSettingsTile(
leading: Icon(
MdiIcons.import,
color: Theme.of(context).colorScheme.primary,
),
CustomSettingsTile(
leading: Icon(
MdiIcons.import,
color: Theme.of(context).colorScheme.primary,
),
title: Text(AppLocalizations.of(context).settingsImport),
onTap: () async {
final settingsExportHelper = _buildSettingsExportHelper(context);
title: Text(AppLocalizations.of(context).settingsImport),
onTap: () async {
final settingsExportHelper = _buildSettingsExportHelper(context);
try {
final result = await FilePicker.platform.pickFiles(
withData: true,
);
try {
final result = await FilePicker.platform.pickFiles(
withData: true,
);
if (result == null) {
return;
}
if (result == null) {
return;
}
if (!result.files.single.path!.endsWith('.json.base64')) {
if (mounted) {
NeonException.showSnackbar(
context,
AppLocalizations.of(context).settingsImportWrongFileExtension,
);
}
return;
if (!result.files.single.path!.endsWith('.json.base64')) {
if (mounted) {
NeonException.showSnackbar(
context,
AppLocalizations.of(context).settingsImportWrongFileExtension,
);
}
return;
}
final data = json.decode(utf8.decode(base64.decode(utf8.decode(result.files.single.bytes!))));
final data = json.decode(utf8.decode(base64.decode(utf8.decode(result.files.single.bytes!))));
await settingsExportHelper.applyFromJson(data as Map<String, dynamic>);
} catch (e, s) {
debugPrint(e.toString());
debugPrint(s.toString());
NeonException.showSnackbar(context, e);
}
},
),
],
),
],
),
);
},
await settingsExportHelper.applyFromJson(data as Map<String, dynamic>);
} catch (e, s) {
debugPrint(e.toString());
debugPrint(s.toString());
NeonException.showSnackbar(context, e);
}
},
),
],
),
],
),
);
},
);
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: appBar,
body: Center(
child: ConstrainedBox(
constraints: NeonDialogTheme.of(context).constraints,
child: body,
),
),
);
}

Loading…
Cancel
Save