Browse Source

Merge pull request #1031 from nextcloud/doc/neon_utils

docs(neon): document neon utils
pull/1055/head
Nikolas Rimikis 1 year ago committed by GitHub
parent
commit
3b949f2cf7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      packages/neon/neon/lib/src/utils/account_options.dart
  2. 1
      packages/neon/neon/lib/src/utils/global.dart
  3. 91
      packages/neon/neon/lib/src/utils/global_options.dart
  4. 14
      packages/neon/neon/lib/src/utils/global_popups.dart
  5. 2
      packages/neon/neon/lib/src/utils/hex_color.dart
  6. 5
      packages/neon/neon/lib/src/utils/save_file.dart
  7. 7
      packages/neon/neon/lib/src/utils/validators.dart

7
packages/neon/neon/lib/src/utils/account_options.dart

@ -5,9 +5,11 @@ import 'package:neon/src/settings/models/option.dart';
import 'package:neon/src/settings/models/options_collection.dart'; import 'package:neon/src/settings/models/options_collection.dart';
import 'package:neon/src/settings/models/storage.dart'; import 'package:neon/src/settings/models/storage.dart';
/// Account related options.
@internal @internal
@immutable @immutable
class AccountSpecificOptions extends OptionsCollection { class AccountSpecificOptions extends OptionsCollection {
/// Creates a new account options collection.
AccountSpecificOptions( AccountSpecificOptions(
super.storage, super.storage,
this._appsBloc, this._appsBloc,
@ -30,6 +32,9 @@ class AccountSpecificOptions extends OptionsCollection {
initialApp, initialApp,
]; ];
/// The initial app to show on app start.
///
/// Defaults to `null` letting the framework choose one.
late final initialApp = SelectOption<String?>( late final initialApp = SelectOption<String?>(
storage: storage, storage: storage,
key: AccountOptionKeys.initialApp, key: AccountOptionKeys.initialApp,
@ -39,8 +44,10 @@ class AccountSpecificOptions extends OptionsCollection {
); );
} }
/// Storage keys for the [AccountSpecificOptions].
@internal @internal
enum AccountOptionKeys implements Storable { enum AccountOptionKeys implements Storable {
/// The storage key for [AccountSpecificOptions.initialApp]
initialApp._('initial-app'); initialApp._('initial-app');
const AccountOptionKeys._(this.value); const AccountOptionKeys._(this.value);

1
packages/neon/neon/lib/src/utils/global.dart

@ -1,6 +1,7 @@
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:neon/src/models/push_notification.dart'; import 'package:neon/src/models/push_notification.dart';
/// Global states handling notification callbacks.
@internal @internal
class Global { class Global {
const Global._(); const Global._();

91
packages/neon/neon/lib/src/utils/global_options.dart

@ -10,11 +10,14 @@ import 'package:package_info_plus/package_info_plus.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:universal_io/io.dart'; import 'package:universal_io/io.dart';
/// The package id of the NextPush UnifiedPush distributor.
const unifiedPushNextPushID = 'org.unifiedpush.distributor.nextpush'; const unifiedPushNextPushID = 'org.unifiedpush.distributor.nextpush';
/// Global options for the Neon framework.
@internal @internal
@immutable @immutable
class GlobalOptions extends OptionsCollection { class GlobalOptions extends OptionsCollection {
/// Creates a new global options collection.
GlobalOptions( GlobalOptions(
this._packageInfo, this._packageInfo,
) : super(const AppStorage(StorageKeys.global)) { ) : super(const AppStorage(StorageKeys.global)) {
@ -89,6 +92,9 @@ class GlobalOptions extends OptionsCollection {
rememberLastUsedAccount.removeListener(_rememberLastUsedAccountListener); rememberLastUsedAccount.removeListener(_rememberLastUsedAccountListener);
} }
/// Updates the available values of [initialAccount].
///
/// If the current `initialAccount` is not supported anymore the option will be reset.
void updateAccounts(final List<Account> accounts) { void updateAccounts(final List<Account> accounts) {
initialAccount.values = Map.fromEntries( initialAccount.values = Map.fromEntries(
accounts.map( accounts.map(
@ -101,6 +107,10 @@ class GlobalOptions extends OptionsCollection {
} }
} }
/// Updates the values of [pushNotificationsDistributor].
///
/// If the new `distributors` does not contain the currently active one
/// both [pushNotificationsDistributor] and [pushNotificationsEnabled] will be reset.
void updateDistributors(final List<String> distributors) { void updateDistributors(final List<String> distributors) {
pushNotificationsDistributor.values = Map.fromEntries( pushNotificationsDistributor.values = Map.fromEntries(
distributors.map( distributors.map(
@ -116,6 +126,7 @@ class GlobalOptions extends OptionsCollection {
} }
} }
/// The theme mode of the app implementing the Neon framework.
late final themeMode = SelectOption( late final themeMode = SelectOption(
storage: storage, storage: storage,
key: GlobalOptionKeys.themeMode, key: GlobalOptionKeys.themeMode,
@ -128,6 +139,10 @@ class GlobalOptions extends OptionsCollection {
}, },
); );
/// Whether the [ThemeMode.dark] should use a plain black background.
///
/// This is commonly used for OLED screens.
/// Defaults to `false`.
late final themeOLEDAsDark = ToggleOption( late final themeOLEDAsDark = ToggleOption(
storage: storage, storage: storage,
key: GlobalOptionKeys.themeOLEDAsDark, key: GlobalOptionKeys.themeOLEDAsDark,
@ -135,6 +150,9 @@ class GlobalOptions extends OptionsCollection {
defaultValue: false, defaultValue: false,
); );
/// Whether the `ColorScheme` should keep the accent color provided by the Nextcloud server.
///
/// Defaults to `false` generating a Material 3 style color.
late final themeKeepOriginalAccentColor = ToggleOption( late final themeKeepOriginalAccentColor = ToggleOption(
storage: storage, storage: storage,
key: GlobalOptionKeys.themeKeepOriginalAccentColor, key: GlobalOptionKeys.themeKeepOriginalAccentColor,
@ -142,6 +160,12 @@ class GlobalOptions extends OptionsCollection {
defaultValue: false, defaultValue: false,
); );
/// Whether to enable the push notifications plugin.
///
/// Setting this option to true will request the permission to show notifications.
/// Disabling this option will reset [pushNotificationsDistributor].
///
/// Defaults to `false`.
late final pushNotificationsEnabled = ToggleOption( late final pushNotificationsEnabled = ToggleOption(
storage: storage, storage: storage,
key: GlobalOptionKeys.pushNotificationsEnabled, key: GlobalOptionKeys.pushNotificationsEnabled,
@ -149,6 +173,7 @@ class GlobalOptions extends OptionsCollection {
defaultValue: false, defaultValue: false,
); );
/// The registered distributor for push notifications.
late final pushNotificationsDistributor = SelectOption<String?>.depend( late final pushNotificationsDistributor = SelectOption<String?>.depend(
storage: storage, storage: storage,
key: GlobalOptionKeys.pushNotificationsDistributor, key: GlobalOptionKeys.pushNotificationsDistributor,
@ -158,6 +183,13 @@ class GlobalOptions extends OptionsCollection {
enabled: pushNotificationsEnabled, enabled: pushNotificationsEnabled,
); );
/// Whether to start the app minimized.
///
/// Defaults to `false`.
///
/// See:
/// * [minimizeInsteadOfExit]: for an option to minimize instead of closing the app.
/// * [systemTrayHideToTrayWhenMinimized]: to minimize the app to system tray.
late final startupMinimized = ToggleOption( late final startupMinimized = ToggleOption(
storage: storage, storage: storage,
key: GlobalOptionKeys.startupMinimized, key: GlobalOptionKeys.startupMinimized,
@ -165,6 +197,13 @@ class GlobalOptions extends OptionsCollection {
defaultValue: false, defaultValue: false,
); );
/// Whether to minimize app instead of closing it.
///
/// Defaults to `false`.
///
/// See:
/// * [startupMinimized]: for an option to startup in the minimized state.
/// * [systemTrayHideToTrayWhenMinimized]: to minimize the app to system tray.
late final startupMinimizeInsteadOfExit = ToggleOption( late final startupMinimizeInsteadOfExit = ToggleOption(
storage: storage, storage: storage,
key: GlobalOptionKeys.startupMinimizeInsteadOfExit, key: GlobalOptionKeys.startupMinimizeInsteadOfExit,
@ -174,6 +213,12 @@ class GlobalOptions extends OptionsCollection {
// TODO: Autostart option // TODO: Autostart option
/// Whether to enable the system tray.
///
/// Defaults to `false`.
///
/// See:
/// * [systemTrayHideToTrayWhenMinimized]: to minimize the app to system tray.
late final systemTrayEnabled = ToggleOption( late final systemTrayEnabled = ToggleOption(
storage: storage, storage: storage,
key: GlobalOptionKeys.systemTrayEnabled, key: GlobalOptionKeys.systemTrayEnabled,
@ -181,6 +226,15 @@ class GlobalOptions extends OptionsCollection {
defaultValue: false, defaultValue: false,
); );
/// Whether to minimize to the system tray or not.
///
/// Requires [systemTrayEnabled] to be true.
/// Defaults to `true`.
///
/// See:
/// * [systemTrayEnabled]: to enable the system tray.
/// * [startupMinimized]: for an option to startup in the minimized state.
/// * [minimizeInsteadOfExit]: for an option to minimize instead of closing the app.
late final systemTrayHideToTrayWhenMinimized = ToggleOption.depend( late final systemTrayHideToTrayWhenMinimized = ToggleOption.depend(
storage: storage, storage: storage,
key: GlobalOptionKeys.systemTrayHideToTrayWhenMinimized, key: GlobalOptionKeys.systemTrayHideToTrayWhenMinimized,
@ -189,6 +243,10 @@ class GlobalOptions extends OptionsCollection {
enabled: systemTrayEnabled, enabled: systemTrayEnabled,
); );
/// Whether to remember the last active account.
///
/// Enabling this option will reset the [initialAccount].
/// Defaults to `true`.
late final rememberLastUsedAccount = ToggleOption( late final rememberLastUsedAccount = ToggleOption(
storage: storage, storage: storage,
key: GlobalOptionKeys.rememberLastUsedAccount, key: GlobalOptionKeys.rememberLastUsedAccount,
@ -196,6 +254,7 @@ class GlobalOptions extends OptionsCollection {
defaultValue: true, defaultValue: true,
); );
/// The initial account to use when opening the app.
late final initialAccount = SelectOption<String?>( late final initialAccount = SelectOption<String?>(
storage: storage, storage: storage,
key: GlobalOptionKeys.initialAccount, key: GlobalOptionKeys.initialAccount,
@ -218,19 +277,43 @@ class GlobalOptions extends OptionsCollection {
); );
} }
/// The storage keys for the [GlobalOptions].
@internal @internal
enum GlobalOptionKeys implements Storable { enum GlobalOptionKeys implements Storable {
/// The storage key for [GlobalOptions.themeMode]
themeMode._('theme-mode'), themeMode._('theme-mode'),
/// The storage key for [GlobalOptions.themeOLEDAsDark]
themeOLEDAsDark._('theme-oled-as-dark'), themeOLEDAsDark._('theme-oled-as-dark'),
/// The storage key for [GlobalOptions.themeKeepOriginalAccentColor]
themeKeepOriginalAccentColor._('theme-keep-original-accent-color'), themeKeepOriginalAccentColor._('theme-keep-original-accent-color'),
/// The storage key for [GlobalOptions.pushNotificationsEnabled]
pushNotificationsEnabled._('push-notifications-enabled'), pushNotificationsEnabled._('push-notifications-enabled'),
/// The storage key for [GlobalOptions.pushNotificationsDistributor]
pushNotificationsDistributor._('push-notifications-distributor'), pushNotificationsDistributor._('push-notifications-distributor'),
/// The storage key for [GlobalOptions.startupMinimized]
startupMinimized._('startup-minimized'), startupMinimized._('startup-minimized'),
/// The storage key for [GlobalOptions.startupMinimizeInsteadOfExit]
startupMinimizeInsteadOfExit._('startup-minimize-instead-of-exit'), startupMinimizeInsteadOfExit._('startup-minimize-instead-of-exit'),
/// The storage key for [GlobalOptions.systemTrayEnabled]
systemTrayEnabled._('system-tray-enabled'), systemTrayEnabled._('system-tray-enabled'),
/// The storage key for [GlobalOptions.systemTrayHideToTrayWhenMinimized]
systemTrayHideToTrayWhenMinimized._('system-tray-hide-to-tray-when-minimized'), systemTrayHideToTrayWhenMinimized._('system-tray-hide-to-tray-when-minimized'),
/// The storage key for [GlobalOptions.rememberLastUsedAccount]
rememberLastUsedAccount._('remember-last-used-account'), rememberLastUsedAccount._('remember-last-used-account'),
/// The storage key for [GlobalOptions.initialAccount]
initialAccount._('initial-account'), initialAccount._('initial-account'),
/// The storage key for [GlobalOptions.navigationMode]
navigationMode._('navigation-mode'); navigationMode._('navigation-mode');
const GlobalOptionKeys._(this.value); const GlobalOptionKeys._(this.value);
@ -239,8 +322,16 @@ enum GlobalOptionKeys implements Storable {
final String value; final String value;
} }
/// App navigation modes.
@internal @internal
enum NavigationMode { enum NavigationMode {
/// Drawer behind a hamburger menu.
///
/// The default for small screen sizes.
drawer, drawer,
/// Persistent drawer on the leading edge.
///
/// The default on large screen sizes.
drawerAlwaysVisible, drawerAlwaysVisible,
} }

14
packages/neon/neon/lib/src/utils/global_popups.dart

@ -12,15 +12,23 @@ import 'package:neon/src/utils/global_options.dart';
import 'package:neon/src/utils/provider.dart'; import 'package:neon/src/utils/provider.dart';
import 'package:url_launcher/url_launcher_string.dart'; import 'package:url_launcher/url_launcher_string.dart';
/// Singleton class managing global popups.
@internal @internal
class GlobalPopups { class GlobalPopups {
/// Returns the current instance.
///
/// Instantiates a new one if not yet present.
factory GlobalPopups() => instance ??= GlobalPopups._(); factory GlobalPopups() => instance ??= GlobalPopups._();
/// Returns the current instance.
///
/// Instantiates a new one with a [mock]ed value if not yet present.
@visibleForTesting @visibleForTesting
factory GlobalPopups.mocked(final GlobalPopups mock) => instance ??= mock; factory GlobalPopups.mocked(final GlobalPopups mock) => instance ??= mock;
GlobalPopups._(); GlobalPopups._();
/// The instance of this singleton.
@visibleForTesting @visibleForTesting
static GlobalPopups? instance; static GlobalPopups? instance;
@ -28,6 +36,9 @@ class GlobalPopups {
late BuildContext _context; late BuildContext _context;
final _subscriptions = <StreamSubscription<dynamic>>[]; final _subscriptions = <StreamSubscription<dynamic>>[];
/// Disposes this instance and cancels all active subscriptions.
///
/// The instance will be reset. Subsequent calls will instantiate a new one.
void dispose() { void dispose() {
for (final subscription in _subscriptions) { for (final subscription in _subscriptions) {
unawaited(subscription.cancel()); unawaited(subscription.cancel());
@ -37,6 +48,9 @@ class GlobalPopups {
instance = null; instance = null;
} }
/// Registers the global backups to the given [context].
///
/// Subsequent calls will update the cached `context` but will not run the registration again.
void register(final BuildContext context) { void register(final BuildContext context) {
_context = context; _context = context;
if (_registered) { if (_registered) {

2
packages/neon/neon/lib/src/utils/hex_color.dart

@ -1,6 +1,8 @@
import 'dart:ui'; import 'dart:ui';
/// A [Color] from a hex string.
class HexColor extends Color { class HexColor extends Color {
/// Creates a new [Color] from the given [hexColor] string.
HexColor(final String hexColor) : super(_parse(hexColor)); HexColor(final String hexColor) : super(_parse(hexColor));
static int _parse(final String hexColor) { static int _parse(final String hexColor) {

5
packages/neon/neon/lib/src/utils/save_file.dart

@ -5,6 +5,11 @@ import 'package:flutter_file_dialog/flutter_file_dialog.dart';
import 'package:neon/src/platform/platform.dart'; import 'package:neon/src/platform/platform.dart';
import 'package:universal_io/io.dart'; import 'package:universal_io/io.dart';
/// Displays a dialog for selecting a location where to save a file with the [data] content.
///
/// Set the the suggested [fileName] to use when saving the file.
///
/// Returns the path of the saved file or `null` if the operation was cancelled.
Future<String?> saveFileWithPickDialog(final String fileName, final Uint8List data) async { Future<String?> saveFileWithPickDialog(final String fileName, final Uint8List data) async {
if (NeonPlatform.instance.shouldUseFileDialog) { if (NeonPlatform.instance.shouldUseFileDialog) {
// TODO: https://github.com/nextcloud/neon/issues/8 // TODO: https://github.com/nextcloud/neon/issues/8

7
packages/neon/neon/lib/src/utils/validators.dart

@ -1,6 +1,10 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:neon/l10n/localizations.dart'; import 'package:neon/l10n/localizations.dart';
/// Validates whether the given [input] is a valid HTTP(S) URL.
///
/// Set [httpsOnly] if you want to only allow HTTPS URLs.
/// Returns `null` if the URL is valid or a localized error message if not.
String? validateHttpUrl( String? validateHttpUrl(
final BuildContext context, final BuildContext context,
final String? input, { final String? input, {
@ -24,6 +28,9 @@ String? validateHttpUrl(
return NeonLocalizations.of(context).errorInvalidURL; return NeonLocalizations.of(context).errorInvalidURL;
} }
/// Validates that the given [input] is neither null nor empty.
///
/// Returns `null` if not empty or a localized error message if empty.
String? validateNotEmpty(final BuildContext context, final String? input) { String? validateNotEmpty(final BuildContext context, final String? input) {
if (input == null || input.isEmpty) { if (input == null || input.isEmpty) {
return NeonLocalizations.of(context).errorEmptyField; return NeonLocalizations.of(context).errorEmptyField;

Loading…
Cancel
Save