From 80455f5ee5546d2d2fc12660e59026b2231647c0 Mon Sep 17 00:00:00 2001 From: Nikolas Rimikis Date: Thu, 26 Oct 2023 08:16:13 +0200 Subject: [PATCH] docs(neon): document neon utils Signed-off-by: Nikolas Rimikis --- .../neon/lib/src/utils/account_options.dart | 7 ++ packages/neon/neon/lib/src/utils/global.dart | 1 + .../neon/lib/src/utils/global_options.dart | 91 +++++++++++++++++++ .../neon/lib/src/utils/global_popups.dart | 14 +++ .../neon/neon/lib/src/utils/hex_color.dart | 2 + .../neon/neon/lib/src/utils/save_file.dart | 5 + .../neon/neon/lib/src/utils/validators.dart | 7 ++ 7 files changed, 127 insertions(+) diff --git a/packages/neon/neon/lib/src/utils/account_options.dart b/packages/neon/neon/lib/src/utils/account_options.dart index 225c2245..4af2fb4f 100644 --- a/packages/neon/neon/lib/src/utils/account_options.dart +++ b/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/storage.dart'; +/// Account related options. @internal @immutable class AccountSpecificOptions extends OptionsCollection { + /// Creates a new account options collection. AccountSpecificOptions( super.storage, this._appsBloc, @@ -30,6 +32,9 @@ class AccountSpecificOptions extends OptionsCollection { initialApp, ]; + /// The initial app to show on app start. + /// + /// Defaults to `null` letting the framework choose one. late final initialApp = SelectOption( storage: storage, key: AccountOptionKeys.initialApp, @@ -39,8 +44,10 @@ class AccountSpecificOptions extends OptionsCollection { ); } +/// Storage keys for the [AccountSpecificOptions]. @internal enum AccountOptionKeys implements Storable { + /// The storage key for [AccountSpecificOptions.initialApp] initialApp._('initial-app'); const AccountOptionKeys._(this.value); diff --git a/packages/neon/neon/lib/src/utils/global.dart b/packages/neon/neon/lib/src/utils/global.dart index 4305e33f..553c1fb8 100644 --- a/packages/neon/neon/lib/src/utils/global.dart +++ b/packages/neon/neon/lib/src/utils/global.dart @@ -1,6 +1,7 @@ import 'package:meta/meta.dart'; import 'package:neon/src/models/push_notification.dart'; +/// Global states handling notification callbacks. @internal class Global { const Global._(); diff --git a/packages/neon/neon/lib/src/utils/global_options.dart b/packages/neon/neon/lib/src/utils/global_options.dart index 99e190d9..075a3439 100644 --- a/packages/neon/neon/lib/src/utils/global_options.dart +++ b/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:universal_io/io.dart'; +/// The package id of the NextPush UnifiedPush distributor. const unifiedPushNextPushID = 'org.unifiedpush.distributor.nextpush'; +/// Global options for the Neon framework. @internal @immutable class GlobalOptions extends OptionsCollection { + /// Creates a new global options collection. GlobalOptions( this._packageInfo, ) : super(const AppStorage(StorageKeys.global)) { @@ -89,6 +92,9 @@ class GlobalOptions extends OptionsCollection { 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 accounts) { initialAccount.values = Map.fromEntries( 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 distributors) { pushNotificationsDistributor.values = Map.fromEntries( distributors.map( @@ -116,6 +126,7 @@ class GlobalOptions extends OptionsCollection { } } + /// The theme mode of the app implementing the Neon framework. late final themeMode = SelectOption( storage: storage, 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( storage: storage, key: GlobalOptionKeys.themeOLEDAsDark, @@ -135,6 +150,9 @@ class GlobalOptions extends OptionsCollection { 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( storage: storage, key: GlobalOptionKeys.themeKeepOriginalAccentColor, @@ -142,6 +160,12 @@ class GlobalOptions extends OptionsCollection { 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( storage: storage, key: GlobalOptionKeys.pushNotificationsEnabled, @@ -149,6 +173,7 @@ class GlobalOptions extends OptionsCollection { defaultValue: false, ); + /// The registered distributor for push notifications. late final pushNotificationsDistributor = SelectOption.depend( storage: storage, key: GlobalOptionKeys.pushNotificationsDistributor, @@ -158,6 +183,13 @@ class GlobalOptions extends OptionsCollection { 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( storage: storage, key: GlobalOptionKeys.startupMinimized, @@ -165,6 +197,13 @@ class GlobalOptions extends OptionsCollection { 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( storage: storage, key: GlobalOptionKeys.startupMinimizeInsteadOfExit, @@ -174,6 +213,12 @@ class GlobalOptions extends OptionsCollection { // 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( storage: storage, key: GlobalOptionKeys.systemTrayEnabled, @@ -181,6 +226,15 @@ class GlobalOptions extends OptionsCollection { 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( storage: storage, key: GlobalOptionKeys.systemTrayHideToTrayWhenMinimized, @@ -189,6 +243,10 @@ class GlobalOptions extends OptionsCollection { enabled: systemTrayEnabled, ); + /// Whether to remember the last active account. + /// + /// Enabling this option will reset the [initialAccount]. + /// Defaults to `true`. late final rememberLastUsedAccount = ToggleOption( storage: storage, key: GlobalOptionKeys.rememberLastUsedAccount, @@ -196,6 +254,7 @@ class GlobalOptions extends OptionsCollection { defaultValue: true, ); + /// The initial account to use when opening the app. late final initialAccount = SelectOption( storage: storage, key: GlobalOptionKeys.initialAccount, @@ -218,19 +277,43 @@ class GlobalOptions extends OptionsCollection { ); } +/// The storage keys for the [GlobalOptions]. @internal enum GlobalOptionKeys implements Storable { + /// The storage key for [GlobalOptions.themeMode] themeMode._('theme-mode'), + + /// The storage key for [GlobalOptions.themeOLEDAsDark] themeOLEDAsDark._('theme-oled-as-dark'), + + /// The storage key for [GlobalOptions.themeKeepOriginalAccentColor] themeKeepOriginalAccentColor._('theme-keep-original-accent-color'), + + /// The storage key for [GlobalOptions.pushNotificationsEnabled] pushNotificationsEnabled._('push-notifications-enabled'), + + /// The storage key for [GlobalOptions.pushNotificationsDistributor] pushNotificationsDistributor._('push-notifications-distributor'), + + /// The storage key for [GlobalOptions.startupMinimized] startupMinimized._('startup-minimized'), + + /// The storage key for [GlobalOptions.startupMinimizeInsteadOfExit] startupMinimizeInsteadOfExit._('startup-minimize-instead-of-exit'), + + /// The storage key for [GlobalOptions.systemTrayEnabled] systemTrayEnabled._('system-tray-enabled'), + + /// The storage key for [GlobalOptions.systemTrayHideToTrayWhenMinimized] systemTrayHideToTrayWhenMinimized._('system-tray-hide-to-tray-when-minimized'), + + /// The storage key for [GlobalOptions.rememberLastUsedAccount] rememberLastUsedAccount._('remember-last-used-account'), + + /// The storage key for [GlobalOptions.initialAccount] initialAccount._('initial-account'), + + /// The storage key for [GlobalOptions.navigationMode] navigationMode._('navigation-mode'); const GlobalOptionKeys._(this.value); @@ -239,8 +322,16 @@ enum GlobalOptionKeys implements Storable { final String value; } +/// App navigation modes. @internal enum NavigationMode { + /// Drawer behind a hamburger menu. + /// + /// The default for small screen sizes. drawer, + + /// Persistent drawer on the leading edge. + /// + /// The default on large screen sizes. drawerAlwaysVisible, } diff --git a/packages/neon/neon/lib/src/utils/global_popups.dart b/packages/neon/neon/lib/src/utils/global_popups.dart index 54ab7e7c..897e28f5 100644 --- a/packages/neon/neon/lib/src/utils/global_popups.dart +++ b/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:url_launcher/url_launcher_string.dart'; +/// Singleton class managing global popups. @internal class GlobalPopups { + /// Returns the current instance. + /// + /// Instantiates a new one if not yet present. factory GlobalPopups() => instance ??= GlobalPopups._(); + /// Returns the current instance. + /// + /// Instantiates a new one with a [mock]ed value if not yet present. @visibleForTesting factory GlobalPopups.mocked(final GlobalPopups mock) => instance ??= mock; GlobalPopups._(); + /// The instance of this singleton. @visibleForTesting static GlobalPopups? instance; @@ -28,6 +36,9 @@ class GlobalPopups { late BuildContext _context; final _subscriptions = >[]; + /// Disposes this instance and cancels all active subscriptions. + /// + /// The instance will be reset. Subsequent calls will instantiate a new one. void dispose() { for (final subscription in _subscriptions) { unawaited(subscription.cancel()); @@ -37,6 +48,9 @@ class GlobalPopups { 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) { _context = context; if (_registered) { diff --git a/packages/neon/neon/lib/src/utils/hex_color.dart b/packages/neon/neon/lib/src/utils/hex_color.dart index 4ac99468..4452ce64 100644 --- a/packages/neon/neon/lib/src/utils/hex_color.dart +++ b/packages/neon/neon/lib/src/utils/hex_color.dart @@ -1,6 +1,8 @@ import 'dart:ui'; +/// A [Color] from a hex string. class HexColor extends Color { + /// Creates a new [Color] from the given [hexColor] string. HexColor(final String hexColor) : super(_parse(hexColor)); static int _parse(final String hexColor) { diff --git a/packages/neon/neon/lib/src/utils/save_file.dart b/packages/neon/neon/lib/src/utils/save_file.dart index b265d881..d25c5286 100644 --- a/packages/neon/neon/lib/src/utils/save_file.dart +++ b/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: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 saveFileWithPickDialog(final String fileName, final Uint8List data) async { if (NeonPlatform.instance.shouldUseFileDialog) { // TODO: https://github.com/nextcloud/neon/issues/8 diff --git a/packages/neon/neon/lib/src/utils/validators.dart b/packages/neon/neon/lib/src/utils/validators.dart index 35942076..7943b817 100644 --- a/packages/neon/neon/lib/src/utils/validators.dart +++ b/packages/neon/neon/lib/src/utils/validators.dart @@ -1,6 +1,10 @@ import 'package:flutter/widgets.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( final BuildContext context, final String? input, { @@ -24,6 +28,9 @@ String? validateHttpUrl( 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) { if (input == null || input.isEmpty) { return NeonLocalizations.of(context).errorEmptyField;