Theme configuration
This commit is contained in:
@@ -1,3 +0,0 @@
|
|||||||
class SharedPreferencesKeys {
|
|
||||||
static const serversInstances = "serversInstances";
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
enum LoadStatus { loading, loaded, error }
|
enum LoadStatus { loading, loaded, error }
|
||||||
|
|
||||||
enum ConnectionMethod { http, https }
|
enum ConnectionMethod { http, https }
|
||||||
|
|
||||||
|
enum SelectedTheme { system, light, dark }
|
||||||
|
|||||||
6
lib/constants/shared_preferences_keys.dart
Normal file
6
lib/constants/shared_preferences_keys.dart
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
class SharedPreferencesKeys {
|
||||||
|
static const serversInstances = "serversInstances";
|
||||||
|
static const selectedTheme = "selectedTheme";
|
||||||
|
static const useDynamicTheme = "useDynamicTheme";
|
||||||
|
static const selectedColor = "selectedColor";
|
||||||
|
}
|
||||||
3
lib/constants/strings.dart
Normal file
3
lib/constants/strings.dart
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
class Strings {
|
||||||
|
static const createdBy = "JGeek00";
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
class Urls {
|
class Urls {
|
||||||
static const linkdingInstallationInstructions =
|
static const linkdingInstallationInstructions =
|
||||||
"https://github.com/sissbruecker/linkding?tab=readme-ov-file#installation";
|
"https://github.com/sissbruecker/linkding?tab=readme-ov-file#installation";
|
||||||
|
static const gitHubRepo = "https://github.com/JGeek00/linkdy";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
/// To regenerate, run: `dart run slang`
|
/// To regenerate, run: `dart run slang`
|
||||||
///
|
///
|
||||||
/// Locales: 2
|
/// Locales: 2
|
||||||
/// Strings: 68 (34 per locale)
|
/// Strings: 122 (61 per locale)
|
||||||
///
|
///
|
||||||
/// Built on 2024-02-22 at 21:21 UTC
|
/// Built on 2024-02-23 at 00:06 UTC
|
||||||
|
|
||||||
// coverage:ignore-file
|
// coverage:ignore-file
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
@@ -153,6 +153,7 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
|
|||||||
late final _StringsSearchEn search = _StringsSearchEn._(_root);
|
late final _StringsSearchEn search = _StringsSearchEn._(_root);
|
||||||
late final _StringsSettingsEn settings = _StringsSettingsEn._(_root);
|
late final _StringsSettingsEn settings = _StringsSettingsEn._(_root);
|
||||||
late final _StringsWebviewEn webview = _StringsWebviewEn._(_root);
|
late final _StringsWebviewEn webview = _StringsWebviewEn._(_root);
|
||||||
|
late final _StringsColorsEn colors = _StringsColorsEn._(_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: onboarding
|
// Path: onboarding
|
||||||
@@ -214,7 +215,17 @@ class _StringsSettingsEn {
|
|||||||
|
|
||||||
// Translations
|
// Translations
|
||||||
String get settings => 'Settings';
|
String get settings => 'Settings';
|
||||||
|
String get appSettings => 'App settings';
|
||||||
String get disconnectFromServer => 'Disconnect from server';
|
String get disconnectFromServer => 'Disconnect from server';
|
||||||
|
String get aboutApp => 'About the app';
|
||||||
|
String get appVersion => 'App version';
|
||||||
|
String get createdBy => 'Created by';
|
||||||
|
String get visitGooglePlay => 'Visit the application page at Google Play';
|
||||||
|
String get visitGitHubRepo => 'Visit the application repository at GitHub';
|
||||||
|
String get customizationDescription => 'Set the app theme and color palette.';
|
||||||
|
String get generalSettings => 'General settings';
|
||||||
|
String get generalSettingsDescription => 'General tweaks for the application.';
|
||||||
|
late final _StringsSettingsCustomizationEn customization = _StringsSettingsCustomizationEn._(_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: webview
|
// Path: webview
|
||||||
@@ -233,6 +244,26 @@ class _StringsWebviewEn {
|
|||||||
String get share => 'Share';
|
String get share => 'Share';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Path: colors
|
||||||
|
class _StringsColorsEn {
|
||||||
|
_StringsColorsEn._(this._root);
|
||||||
|
|
||||||
|
final Translations _root; // ignore: unused_field
|
||||||
|
|
||||||
|
// Translations
|
||||||
|
String get red => 'Red';
|
||||||
|
String get green => 'Green';
|
||||||
|
String get blue => 'Blue';
|
||||||
|
String get yellow => 'Yellow';
|
||||||
|
String get orange => 'Orange';
|
||||||
|
String get brown => 'Brown';
|
||||||
|
String get cyan => 'Cyan';
|
||||||
|
String get purple => 'Purple';
|
||||||
|
String get pink => 'Pink';
|
||||||
|
String get deepOrange => 'Deep orange';
|
||||||
|
String get indigo => 'Indigo';
|
||||||
|
}
|
||||||
|
|
||||||
// Path: links.dates
|
// Path: links.dates
|
||||||
class _StringsLinksDatesEn {
|
class _StringsLinksDatesEn {
|
||||||
_StringsLinksDatesEn._(this._root);
|
_StringsLinksDatesEn._(this._root);
|
||||||
@@ -244,6 +275,22 @@ class _StringsLinksDatesEn {
|
|||||||
String yesterdayAt({required Object time}) => 'Yesterday, ${time}';
|
String yesterdayAt({required Object time}) => 'Yesterday, ${time}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Path: settings.customization
|
||||||
|
class _StringsSettingsCustomizationEn {
|
||||||
|
_StringsSettingsCustomizationEn._(this._root);
|
||||||
|
|
||||||
|
final Translations _root; // ignore: unused_field
|
||||||
|
|
||||||
|
// Translations
|
||||||
|
String get customization => 'Customization';
|
||||||
|
String get theme => 'Theme';
|
||||||
|
String get light => 'Light';
|
||||||
|
String get dark => 'Dark';
|
||||||
|
String get systemDefined => 'System defined';
|
||||||
|
String get color => 'Color';
|
||||||
|
String get useDynamicTheme => 'Use dynamic theme';
|
||||||
|
}
|
||||||
|
|
||||||
// Path: <root>
|
// Path: <root>
|
||||||
class _StringsEs implements Translations {
|
class _StringsEs implements Translations {
|
||||||
/// You can call this constructor and build your own translation instance of this locale.
|
/// You can call this constructor and build your own translation instance of this locale.
|
||||||
@@ -273,6 +320,7 @@ class _StringsEs implements Translations {
|
|||||||
@override late final _StringsSearchEs search = _StringsSearchEs._(_root);
|
@override late final _StringsSearchEs search = _StringsSearchEs._(_root);
|
||||||
@override late final _StringsSettingsEs settings = _StringsSettingsEs._(_root);
|
@override late final _StringsSettingsEs settings = _StringsSettingsEs._(_root);
|
||||||
@override late final _StringsWebviewEs webview = _StringsWebviewEs._(_root);
|
@override late final _StringsWebviewEs webview = _StringsWebviewEs._(_root);
|
||||||
|
@override late final _StringsColorsEs colors = _StringsColorsEs._(_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: onboarding
|
// Path: onboarding
|
||||||
@@ -334,7 +382,17 @@ class _StringsSettingsEs implements _StringsSettingsEn {
|
|||||||
|
|
||||||
// Translations
|
// Translations
|
||||||
@override String get settings => 'Ajustes';
|
@override String get settings => 'Ajustes';
|
||||||
|
@override String get appSettings => 'Ajustes de la aplicación';
|
||||||
@override String get disconnectFromServer => 'Desconectar del servidor';
|
@override String get disconnectFromServer => 'Desconectar del servidor';
|
||||||
|
@override String get aboutApp => 'Sobre la aplicación';
|
||||||
|
@override String get appVersion => 'Versión de la aplicación';
|
||||||
|
@override String get createdBy => 'Creado por';
|
||||||
|
@override String get visitGooglePlay => 'Visita la página de la aplicación en Google Play';
|
||||||
|
@override String get visitGitHubRepo => 'Visita el repositorio de la aplicación en GitHub';
|
||||||
|
@override String get customizationDescription => 'Configura el tema y la paleta de colores.';
|
||||||
|
@override String get generalSettings => 'Ajustes generales';
|
||||||
|
@override String get generalSettingsDescription => 'Ajustes generales para la aplicación.';
|
||||||
|
@override late final _StringsSettingsCustomizationEs customization = _StringsSettingsCustomizationEs._(_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: webview
|
// Path: webview
|
||||||
@@ -353,6 +411,26 @@ class _StringsWebviewEs implements _StringsWebviewEn {
|
|||||||
@override String get share => 'Compartir';
|
@override String get share => 'Compartir';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Path: colors
|
||||||
|
class _StringsColorsEs implements _StringsColorsEn {
|
||||||
|
_StringsColorsEs._(this._root);
|
||||||
|
|
||||||
|
@override final _StringsEs _root; // ignore: unused_field
|
||||||
|
|
||||||
|
// Translations
|
||||||
|
@override String get red => 'Rojo';
|
||||||
|
@override String get green => 'Verde';
|
||||||
|
@override String get blue => 'Azul';
|
||||||
|
@override String get yellow => 'Amarillo';
|
||||||
|
@override String get orange => 'Naranja';
|
||||||
|
@override String get brown => 'Marron';
|
||||||
|
@override String get cyan => 'Cian';
|
||||||
|
@override String get purple => 'Morado';
|
||||||
|
@override String get pink => 'Rosa';
|
||||||
|
@override String get deepOrange => 'Naranja oscuro';
|
||||||
|
@override String get indigo => 'Índigo';
|
||||||
|
}
|
||||||
|
|
||||||
// Path: links.dates
|
// Path: links.dates
|
||||||
class _StringsLinksDatesEs implements _StringsLinksDatesEn {
|
class _StringsLinksDatesEs implements _StringsLinksDatesEn {
|
||||||
_StringsLinksDatesEs._(this._root);
|
_StringsLinksDatesEs._(this._root);
|
||||||
@@ -364,6 +442,22 @@ class _StringsLinksDatesEs implements _StringsLinksDatesEn {
|
|||||||
@override String yesterdayAt({required Object time}) => 'Ayer, ${time}';
|
@override String yesterdayAt({required Object time}) => 'Ayer, ${time}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Path: settings.customization
|
||||||
|
class _StringsSettingsCustomizationEs implements _StringsSettingsCustomizationEn {
|
||||||
|
_StringsSettingsCustomizationEs._(this._root);
|
||||||
|
|
||||||
|
@override final _StringsEs _root; // ignore: unused_field
|
||||||
|
|
||||||
|
// Translations
|
||||||
|
@override String get customization => 'Personalización';
|
||||||
|
@override String get theme => 'Tema';
|
||||||
|
@override String get light => 'Claro';
|
||||||
|
@override String get dark => 'Oscuro';
|
||||||
|
@override String get systemDefined => 'Definido por el sistema';
|
||||||
|
@override String get color => 'Color';
|
||||||
|
@override String get useDynamicTheme => 'Usar tema dinámico';
|
||||||
|
}
|
||||||
|
|
||||||
/// Flat map(s) containing all translations.
|
/// Flat map(s) containing all translations.
|
||||||
/// Only for edge cases! For simple maps, use the map function of this library.
|
/// Only for edge cases! For simple maps, use the map function of this library.
|
||||||
|
|
||||||
@@ -396,7 +490,23 @@ extension on Translations {
|
|||||||
case 'links.dates.yesterdayAt': return ({required Object time}) => 'Yesterday, ${time}';
|
case 'links.dates.yesterdayAt': return ({required Object time}) => 'Yesterday, ${time}';
|
||||||
case 'search.search': return 'Search';
|
case 'search.search': return 'Search';
|
||||||
case 'settings.settings': return 'Settings';
|
case 'settings.settings': return 'Settings';
|
||||||
|
case 'settings.appSettings': return 'App settings';
|
||||||
case 'settings.disconnectFromServer': return 'Disconnect from server';
|
case 'settings.disconnectFromServer': return 'Disconnect from server';
|
||||||
|
case 'settings.aboutApp': return 'About the app';
|
||||||
|
case 'settings.appVersion': return 'App version';
|
||||||
|
case 'settings.createdBy': return 'Created by';
|
||||||
|
case 'settings.visitGooglePlay': return 'Visit the application page at Google Play';
|
||||||
|
case 'settings.visitGitHubRepo': return 'Visit the application repository at GitHub';
|
||||||
|
case 'settings.customizationDescription': return 'Set the app theme and color palette.';
|
||||||
|
case 'settings.generalSettings': return 'General settings';
|
||||||
|
case 'settings.generalSettingsDescription': return 'General tweaks for the application.';
|
||||||
|
case 'settings.customization.customization': return 'Customization';
|
||||||
|
case 'settings.customization.theme': return 'Theme';
|
||||||
|
case 'settings.customization.light': return 'Light';
|
||||||
|
case 'settings.customization.dark': return 'Dark';
|
||||||
|
case 'settings.customization.systemDefined': return 'System defined';
|
||||||
|
case 'settings.customization.color': return 'Color';
|
||||||
|
case 'settings.customization.useDynamicTheme': return 'Use dynamic theme';
|
||||||
case 'webview.goBack': return 'Go back';
|
case 'webview.goBack': return 'Go back';
|
||||||
case 'webview.goForward': return 'Go forward';
|
case 'webview.goForward': return 'Go forward';
|
||||||
case 'webview.reload': return 'Reload';
|
case 'webview.reload': return 'Reload';
|
||||||
@@ -404,6 +514,17 @@ extension on Translations {
|
|||||||
case 'webview.copyLinkClipboard': return 'Copy link to clipboard';
|
case 'webview.copyLinkClipboard': return 'Copy link to clipboard';
|
||||||
case 'webview.linkCopiedClipboard': return 'Link copied to the clipboard.';
|
case 'webview.linkCopiedClipboard': return 'Link copied to the clipboard.';
|
||||||
case 'webview.share': return 'Share';
|
case 'webview.share': return 'Share';
|
||||||
|
case 'colors.red': return 'Red';
|
||||||
|
case 'colors.green': return 'Green';
|
||||||
|
case 'colors.blue': return 'Blue';
|
||||||
|
case 'colors.yellow': return 'Yellow';
|
||||||
|
case 'colors.orange': return 'Orange';
|
||||||
|
case 'colors.brown': return 'Brown';
|
||||||
|
case 'colors.cyan': return 'Cyan';
|
||||||
|
case 'colors.purple': return 'Purple';
|
||||||
|
case 'colors.pink': return 'Pink';
|
||||||
|
case 'colors.deepOrange': return 'Deep orange';
|
||||||
|
case 'colors.indigo': return 'Indigo';
|
||||||
default: return null;
|
default: return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -438,7 +559,23 @@ extension on _StringsEs {
|
|||||||
case 'links.dates.yesterdayAt': return ({required Object time}) => 'Ayer, ${time}';
|
case 'links.dates.yesterdayAt': return ({required Object time}) => 'Ayer, ${time}';
|
||||||
case 'search.search': return 'Buscar';
|
case 'search.search': return 'Buscar';
|
||||||
case 'settings.settings': return 'Ajustes';
|
case 'settings.settings': return 'Ajustes';
|
||||||
|
case 'settings.appSettings': return 'Ajustes de la aplicación';
|
||||||
case 'settings.disconnectFromServer': return 'Desconectar del servidor';
|
case 'settings.disconnectFromServer': return 'Desconectar del servidor';
|
||||||
|
case 'settings.aboutApp': return 'Sobre la aplicación';
|
||||||
|
case 'settings.appVersion': return 'Versión de la aplicación';
|
||||||
|
case 'settings.createdBy': return 'Creado por';
|
||||||
|
case 'settings.visitGooglePlay': return 'Visita la página de la aplicación en Google Play';
|
||||||
|
case 'settings.visitGitHubRepo': return 'Visita el repositorio de la aplicación en GitHub';
|
||||||
|
case 'settings.customizationDescription': return 'Configura el tema y la paleta de colores.';
|
||||||
|
case 'settings.generalSettings': return 'Ajustes generales';
|
||||||
|
case 'settings.generalSettingsDescription': return 'Ajustes generales para la aplicación.';
|
||||||
|
case 'settings.customization.customization': return 'Personalización';
|
||||||
|
case 'settings.customization.theme': return 'Tema';
|
||||||
|
case 'settings.customization.light': return 'Claro';
|
||||||
|
case 'settings.customization.dark': return 'Oscuro';
|
||||||
|
case 'settings.customization.systemDefined': return 'Definido por el sistema';
|
||||||
|
case 'settings.customization.color': return 'Color';
|
||||||
|
case 'settings.customization.useDynamicTheme': return 'Usar tema dinámico';
|
||||||
case 'webview.goBack': return 'Ir atrás';
|
case 'webview.goBack': return 'Ir atrás';
|
||||||
case 'webview.goForward': return 'Ir adelante';
|
case 'webview.goForward': return 'Ir adelante';
|
||||||
case 'webview.reload': return 'Recargar';
|
case 'webview.reload': return 'Recargar';
|
||||||
@@ -446,6 +583,17 @@ extension on _StringsEs {
|
|||||||
case 'webview.copyLinkClipboard': return 'Copiar enlace al portapapeles';
|
case 'webview.copyLinkClipboard': return 'Copiar enlace al portapapeles';
|
||||||
case 'webview.linkCopiedClipboard': return 'Enlace copiado al portapapeles.';
|
case 'webview.linkCopiedClipboard': return 'Enlace copiado al portapapeles.';
|
||||||
case 'webview.share': return 'Compartir';
|
case 'webview.share': return 'Compartir';
|
||||||
|
case 'colors.red': return 'Rojo';
|
||||||
|
case 'colors.green': return 'Verde';
|
||||||
|
case 'colors.blue': return 'Azul';
|
||||||
|
case 'colors.yellow': return 'Amarillo';
|
||||||
|
case 'colors.orange': return 'Naranja';
|
||||||
|
case 'colors.brown': return 'Marron';
|
||||||
|
case 'colors.cyan': return 'Cian';
|
||||||
|
case 'colors.purple': return 'Morado';
|
||||||
|
case 'colors.pink': return 'Rosa';
|
||||||
|
case 'colors.deepOrange': return 'Naranja oscuro';
|
||||||
|
case 'colors.indigo': return 'Índigo';
|
||||||
default: return null;
|
default: return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,25 @@
|
|||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"settings": "Settings",
|
"settings": "Settings",
|
||||||
"disconnectFromServer": "Disconnect from server"
|
"appSettings": "App settings",
|
||||||
|
"disconnectFromServer": "Disconnect from server",
|
||||||
|
"aboutApp": "About the app",
|
||||||
|
"appVersion": "App version",
|
||||||
|
"createdBy": "Created by",
|
||||||
|
"visitGooglePlay": "Visit the application page at Google Play",
|
||||||
|
"visitGitHubRepo": "Visit the application repository at GitHub",
|
||||||
|
"customizationDescription": "Set the app theme and color palette.",
|
||||||
|
"generalSettings": "General settings",
|
||||||
|
"generalSettingsDescription": "General tweaks for the application.",
|
||||||
|
"customization": {
|
||||||
|
"customization": "Customization",
|
||||||
|
"theme": "Theme",
|
||||||
|
"light": "Light",
|
||||||
|
"dark": "Dark",
|
||||||
|
"systemDefined": "System defined",
|
||||||
|
"color": "Color",
|
||||||
|
"useDynamicTheme": "Use dynamic theme"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"webview": {
|
"webview": {
|
||||||
"goBack": "Go back",
|
"goBack": "Go back",
|
||||||
@@ -44,5 +62,18 @@
|
|||||||
"copyLinkClipboard": "Copy link to clipboard",
|
"copyLinkClipboard": "Copy link to clipboard",
|
||||||
"linkCopiedClipboard": "Link copied to the clipboard.",
|
"linkCopiedClipboard": "Link copied to the clipboard.",
|
||||||
"share": "Share"
|
"share": "Share"
|
||||||
|
},
|
||||||
|
"colors": {
|
||||||
|
"red": "Red",
|
||||||
|
"green": "Green",
|
||||||
|
"blue": "Blue",
|
||||||
|
"yellow": "Yellow",
|
||||||
|
"orange": "Orange",
|
||||||
|
"brown": "Brown",
|
||||||
|
"cyan": "Cyan",
|
||||||
|
"purple": "Purple",
|
||||||
|
"pink": "Pink",
|
||||||
|
"deepOrange": "Deep orange",
|
||||||
|
"indigo": "Indigo"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,25 @@
|
|||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"settings": "Ajustes",
|
"settings": "Ajustes",
|
||||||
"disconnectFromServer": "Desconectar del servidor"
|
"appSettings": "Ajustes de la aplicación",
|
||||||
|
"disconnectFromServer": "Desconectar del servidor",
|
||||||
|
"aboutApp": "Sobre la aplicación",
|
||||||
|
"appVersion": "Versión de la aplicación",
|
||||||
|
"createdBy": "Creado por",
|
||||||
|
"visitGooglePlay": "Visita la página de la aplicación en Google Play",
|
||||||
|
"visitGitHubRepo": "Visita el repositorio de la aplicación en GitHub",
|
||||||
|
"customizationDescription": "Configura el tema y la paleta de colores.",
|
||||||
|
"generalSettings": "Ajustes generales",
|
||||||
|
"generalSettingsDescription": "Ajustes generales para la aplicación.",
|
||||||
|
"customization": {
|
||||||
|
"customization": "Personalización",
|
||||||
|
"theme": "Tema",
|
||||||
|
"light": "Claro",
|
||||||
|
"dark": "Oscuro",
|
||||||
|
"systemDefined": "Definido por el sistema",
|
||||||
|
"color": "Color",
|
||||||
|
"useDynamicTheme": "Usar tema dinámico"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"webview": {
|
"webview": {
|
||||||
"goBack": "Ir atrás",
|
"goBack": "Ir atrás",
|
||||||
@@ -44,5 +62,18 @@
|
|||||||
"copyLinkClipboard": "Copiar enlace al portapapeles",
|
"copyLinkClipboard": "Copiar enlace al portapapeles",
|
||||||
"linkCopiedClipboard": "Enlace copiado al portapapeles.",
|
"linkCopiedClipboard": "Enlace copiado al portapapeles.",
|
||||||
"share": "Compartir"
|
"share": "Compartir"
|
||||||
|
},
|
||||||
|
"colors": {
|
||||||
|
"red": "Rojo",
|
||||||
|
"green": "Verde",
|
||||||
|
"blue": "Azul",
|
||||||
|
"yellow": "Amarillo",
|
||||||
|
"orange": "Naranja",
|
||||||
|
"brown": "Marron",
|
||||||
|
"cyan": "Cian",
|
||||||
|
"purple": "Morado",
|
||||||
|
"pink": "Rosa",
|
||||||
|
"deepOrange": "Naranja oscuro",
|
||||||
|
"indigo": "Índigo"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,8 +6,11 @@ import 'package:flutter_localizations/flutter_localizations.dart';
|
|||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:linkdy/constants/global_keys.dart';
|
import 'package:linkdy/constants/global_keys.dart';
|
||||||
import 'package:dynamic_color/dynamic_color.dart';
|
import 'package:dynamic_color/dynamic_color.dart';
|
||||||
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
import 'package:linkdy/providers/app_status_provider.dart';
|
||||||
|
import 'package:linkdy/providers/app_info_provider.dart';
|
||||||
import 'package:linkdy/config/theme.dart';
|
import 'package:linkdy/config/theme.dart';
|
||||||
import 'package:linkdy/constants/colors.dart';
|
import 'package:linkdy/constants/colors.dart';
|
||||||
import 'package:linkdy/i18n/strings.g.dart';
|
import 'package:linkdy/i18n/strings.g.dart';
|
||||||
@@ -25,11 +28,14 @@ void main() async {
|
|||||||
|
|
||||||
final sharedPreferences = await SharedPreferences.getInstance();
|
final sharedPreferences = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
|
final appInfo = await PackageInfo.fromPlatform();
|
||||||
|
|
||||||
runApp(
|
runApp(
|
||||||
TranslationProvider(
|
TranslationProvider(
|
||||||
child: ProviderScope(
|
child: ProviderScope(
|
||||||
overrides: [
|
overrides: [
|
||||||
sharedPreferencesProvider.overrideWithValue(sharedPreferences),
|
sharedPreferencesProvider.overrideWithValue(sharedPreferences),
|
||||||
|
appInfoProvider.overrideWithValue(appInfo),
|
||||||
],
|
],
|
||||||
child: const MyApp(),
|
child: const MyApp(),
|
||||||
),
|
),
|
||||||
@@ -42,18 +48,33 @@ class MyApp extends ConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final selectedColor = ref.watch(appStatusProvider).selectedColor;
|
||||||
|
final useDynamicColor = ref.watch(appStatusProvider).useDynamicTheme;
|
||||||
|
|
||||||
return DynamicColorBuilder(
|
return DynamicColorBuilder(
|
||||||
builder: (lightDynamic, darkDynamic) => MaterialApp.router(
|
builder: (lightDynamic, darkDynamic) {
|
||||||
title: 'Linkdy',
|
ref.read(appStatusProvider.notifier).setSupportsDynamicTheme(lightDynamic != null && darkDynamic != null);
|
||||||
theme: lightDynamic != null ? lightTheme(lightDynamic) : lightThemeOldVersions(colors[0]),
|
return MaterialApp.router(
|
||||||
darkTheme: darkDynamic != null ? darkTheme(darkDynamic) : darkThemeOldVersions(colors[0]),
|
title: 'Linkdy',
|
||||||
locale: TranslationProvider.of(context).flutterLocale,
|
theme: lightDynamic != null
|
||||||
supportedLocales: AppLocaleUtils.supportedLocales,
|
? useDynamicColor == true
|
||||||
localizationsDelegates: GlobalMaterialLocalizations.delegates,
|
? lightTheme(lightDynamic)
|
||||||
debugShowCheckedModeBanner: false,
|
: lightThemeOldVersions(colors[selectedColor])
|
||||||
scaffoldMessengerKey: scaffoldMessengerGlobalKey,
|
: lightThemeOldVersions(colors[selectedColor]),
|
||||||
routerConfig: ref.watch(routerProvider),
|
darkTheme: darkDynamic != null
|
||||||
),
|
? useDynamicColor == true
|
||||||
|
? darkTheme(darkDynamic)
|
||||||
|
: darkThemeOldVersions(colors[selectedColor])
|
||||||
|
: darkThemeOldVersions(colors[selectedColor]),
|
||||||
|
themeMode: ref.watch(selectedThemeProvider),
|
||||||
|
locale: TranslationProvider.of(context).flutterLocale,
|
||||||
|
supportedLocales: AppLocaleUtils.supportedLocales,
|
||||||
|
localizationsDelegates: GlobalMaterialLocalizations.delegates,
|
||||||
|
debugShowCheckedModeBanner: false,
|
||||||
|
scaffoldMessengerKey: scaffoldMessengerGlobalKey,
|
||||||
|
routerConfig: ref.watch(routerProvider),
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import 'package:linkdy/models/server_instance.dart';
|
import 'package:linkdy/constants/enums.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
|
||||||
|
|
||||||
class AppStatus {
|
class AppStatusModel {
|
||||||
AppStatus();
|
SelectedTheme selectedTheme;
|
||||||
|
bool supportsDynamicTheme;
|
||||||
|
bool useDynamicTheme;
|
||||||
|
int selectedColor;
|
||||||
|
|
||||||
AppStatus copyWith({
|
AppStatusModel({
|
||||||
SharedPreferences? sharedPreferences,
|
this.selectedTheme = SelectedTheme.system,
|
||||||
ServerInstance? serverInstance,
|
this.supportsDynamicTheme = false,
|
||||||
}) =>
|
this.useDynamicTheme = true,
|
||||||
AppStatus();
|
this.selectedColor = 0,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
9
lib/providers/app_info_provider.dart
Normal file
9
lib/providers/app_info_provider.dart
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
|
part 'app_info_provider.g.dart';
|
||||||
|
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
PackageInfo appInfo(AppInfoRef ref) {
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
24
lib/providers/app_info_provider.g.dart
Normal file
24
lib/providers/app_info_provider.g.dart
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'app_info_provider.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$appInfoHash() => r'c1b99fe8e0ba1b1ba04aa2c1ae066a3de9f1dac1';
|
||||||
|
|
||||||
|
/// See also [appInfo].
|
||||||
|
@ProviderFor(appInfo)
|
||||||
|
final appInfoProvider = Provider<PackageInfo>.internal(
|
||||||
|
appInfo,
|
||||||
|
name: r'appInfoProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product') ? null : _$appInfoHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef AppInfoRef = ProviderRef<PackageInfo>;
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
||||||
@@ -1,18 +1,62 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/scheduler.dart';
|
||||||
|
import 'package:linkdy/constants/shared_preferences_keys.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
|
import 'package:linkdy/providers/shared_preferences_provider.dart';
|
||||||
|
import 'package:linkdy/constants/enums.dart';
|
||||||
import 'package:linkdy/models/app_status.dart';
|
import 'package:linkdy/models/app_status.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
|
||||||
|
|
||||||
part 'app_status_provider.g.dart';
|
part 'app_status_provider.g.dart';
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
class AppStatusProvider extends _$AppStatusProvider {
|
class AppStatus extends _$AppStatus {
|
||||||
@override
|
@override
|
||||||
AppStatus build() {
|
AppStatusModel build() {
|
||||||
return AppStatus();
|
final sharedPreferences = ref.watch(sharedPreferencesProvider);
|
||||||
|
return AppStatusModel(
|
||||||
|
selectedColor: sharedPreferences.getInt(SharedPreferencesKeys.selectedColor) ?? 0,
|
||||||
|
selectedTheme: SelectedTheme.values[sharedPreferences.getInt(SharedPreferencesKeys.selectedTheme) ?? 0],
|
||||||
|
useDynamicTheme: sharedPreferences.getBool(SharedPreferencesKeys.useDynamicTheme) ?? true,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSharedPreferencesInstance(SharedPreferences instance) {
|
void setTheme(SelectedTheme theme) {
|
||||||
state = state.copyWith(sharedPreferences: instance);
|
state.selectedTheme = theme;
|
||||||
|
ref.read(sharedPreferencesProvider).setInt(SharedPreferencesKeys.selectedTheme, theme.index);
|
||||||
|
ref.notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSupportsDynamicTheme(bool value) {
|
||||||
|
state.supportsDynamicTheme = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setUseDynamicTheme(bool value) {
|
||||||
|
state.useDynamicTheme = value;
|
||||||
|
ref.read(sharedPreferencesProvider).setBool(SharedPreferencesKeys.useDynamicTheme, value);
|
||||||
|
ref.notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSelectedColor(int value) {
|
||||||
|
state.selectedColor = value;
|
||||||
|
ref.read(sharedPreferencesProvider).setInt(SharedPreferencesKeys.selectedColor, value);
|
||||||
|
ref.notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
ThemeMode selectedTheme(SelectedThemeRef ref) {
|
||||||
|
switch (ref.watch(appStatusProvider).selectedTheme) {
|
||||||
|
case SelectedTheme.system:
|
||||||
|
return SchedulerBinding.instance.window.platformBrightness == Brightness.light ? ThemeMode.light : ThemeMode.dark;
|
||||||
|
|
||||||
|
case SelectedTheme.light:
|
||||||
|
return ThemeMode.light;
|
||||||
|
|
||||||
|
case SelectedTheme.dark:
|
||||||
|
return ThemeMode.dark;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ThemeMode.light;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,21 +6,34 @@ part of 'app_status_provider.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$appStatusProviderHash() => r'ba585a0cf3cf46f88f5895eacec3e992bf0cd42f';
|
String _$selectedThemeHash() => r'b820484a59ed72419c5b4cad0b894a030b54c702';
|
||||||
|
|
||||||
/// See also [AppStatusProvider].
|
/// See also [selectedTheme].
|
||||||
@ProviderFor(AppStatusProvider)
|
@ProviderFor(selectedTheme)
|
||||||
final appStatusProviderProvider =
|
final selectedThemeProvider = AutoDisposeProvider<ThemeMode>.internal(
|
||||||
NotifierProvider<AppStatusProvider, AppStatus>.internal(
|
selectedTheme,
|
||||||
AppStatusProvider.new,
|
name: r'selectedThemeProvider',
|
||||||
name: r'appStatusProviderProvider',
|
|
||||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||||
? null
|
? null
|
||||||
: _$appStatusProviderHash,
|
: _$selectedThemeHash,
|
||||||
dependencies: null,
|
dependencies: null,
|
||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
typedef _$AppStatusProvider = Notifier<AppStatus>;
|
typedef SelectedThemeRef = AutoDisposeProviderRef<ThemeMode>;
|
||||||
|
String _$appStatusHash() => r'cde4567157dd5a89f842a2818efc199db3585232';
|
||||||
|
|
||||||
|
/// See also [AppStatus].
|
||||||
|
@ProviderFor(AppStatus)
|
||||||
|
final appStatusProvider = NotifierProvider<AppStatus, AppStatusModel>.internal(
|
||||||
|
AppStatus.new,
|
||||||
|
name: r'appStatusProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product') ? null : _$appStatusHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef _$AppStatus = Notifier<AppStatusModel>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:linkdy/config/shared_preferences_keys.dart';
|
import 'package:linkdy/constants/shared_preferences_keys.dart';
|
||||||
import 'package:linkdy/providers/shared_preferences_provider.dart';
|
import 'package:linkdy/providers/shared_preferences_provider.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
final sharedPreferencesProvider = Provider<SharedPreferences>((ref) {
|
part 'shared_preferences_provider.g.dart';
|
||||||
|
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
SharedPreferences sharedPreferences(SharedPreferencesRef ref) {
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
});
|
}
|
||||||
|
|||||||
25
lib/providers/shared_preferences_provider.g.dart
Normal file
25
lib/providers/shared_preferences_provider.g.dart
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'shared_preferences_provider.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$sharedPreferencesHash() => r'3a9f8412df34c1653d08100c9826aa2125b80f7f';
|
||||||
|
|
||||||
|
/// See also [sharedPreferences].
|
||||||
|
@ProviderFor(sharedPreferences)
|
||||||
|
final sharedPreferencesProvider = Provider<SharedPreferences>.internal(
|
||||||
|
sharedPreferences,
|
||||||
|
name: r'sharedPreferencesProvider',
|
||||||
|
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$sharedPreferencesHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef SharedPreferencesRef = ProviderRef<SharedPreferences>;
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
||||||
@@ -4,4 +4,5 @@ class RoutesPaths {
|
|||||||
static const webview = "/webview";
|
static const webview = "/webview";
|
||||||
static const search = "/search";
|
static const search = "/search";
|
||||||
static const settings = "/settings";
|
static const settings = "/settings";
|
||||||
|
static const customization = "/settings/customization";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:go_router/go_router.dart';
|
|||||||
import 'package:linkdy/screens/links/ui/links.dart';
|
import 'package:linkdy/screens/links/ui/links.dart';
|
||||||
import 'package:linkdy/screens/onboarding/ui/onboarding.dart';
|
import 'package:linkdy/screens/onboarding/ui/onboarding.dart';
|
||||||
import 'package:linkdy/screens/search/ui/search.dart';
|
import 'package:linkdy/screens/search/ui/search.dart';
|
||||||
|
import 'package:linkdy/screens/settings/ui/customization/customization.dart';
|
||||||
import 'package:linkdy/screens/settings/ui/settings.dart';
|
import 'package:linkdy/screens/settings/ui/settings.dart';
|
||||||
import 'package:linkdy/screens/webview/ui/webview.dart';
|
import 'package:linkdy/screens/webview/ui/webview.dart';
|
||||||
import 'package:linkdy/widgets/layout.dart';
|
import 'package:linkdy/widgets/layout.dart';
|
||||||
@@ -58,6 +59,10 @@ final List<RouteBase> appRoutes = [
|
|||||||
path: RoutesPaths.settings,
|
path: RoutesPaths.settings,
|
||||||
builder: (context, state) => const Settings(),
|
builder: (context, state) => const Settings(),
|
||||||
),
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: RoutesPaths.customization,
|
||||||
|
builder: (context, state) => const Customization(),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
9
lib/screens/settings/model/customization.model.dart
Normal file
9
lib/screens/settings/model/customization.model.dart
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class CustomizationModel {
|
||||||
|
ScrollController? scrollController;
|
||||||
|
|
||||||
|
CustomizationModel({
|
||||||
|
this.scrollController,
|
||||||
|
});
|
||||||
|
}
|
||||||
16
lib/screens/settings/provider/customization.provider.dart
Normal file
16
lib/screens/settings/provider/customization.provider.dart
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
|
import 'package:linkdy/screens/settings/model/customization.model.dart';
|
||||||
|
|
||||||
|
part 'customization.provider.g.dart';
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
class Customization extends _$Customization {
|
||||||
|
@override
|
||||||
|
CustomizationModel build() {
|
||||||
|
return CustomizationModel(
|
||||||
|
scrollController: ScrollController(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
26
lib/screens/settings/provider/customization.provider.g.dart
Normal file
26
lib/screens/settings/provider/customization.provider.g.dart
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'customization.provider.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$customizationHash() => r'c4cf4b566abbe697ec14c5024e1576f230d3e9fb';
|
||||||
|
|
||||||
|
/// See also [Customization].
|
||||||
|
@ProviderFor(Customization)
|
||||||
|
final customizationProvider =
|
||||||
|
AutoDisposeNotifierProvider<Customization, CustomizationModel>.internal(
|
||||||
|
Customization.new,
|
||||||
|
name: r'customizationProvider',
|
||||||
|
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$customizationHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef _$Customization = AutoDisposeNotifier<CustomizationModel>;
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
||||||
57
lib/screens/settings/ui/customization/color_item.dart
Normal file
57
lib/screens/settings/ui/customization/color_item.dart
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class ColorItem extends StatelessWidget {
|
||||||
|
final int index;
|
||||||
|
final int total;
|
||||||
|
final Color color;
|
||||||
|
final int numericValue;
|
||||||
|
final int? selectedValue;
|
||||||
|
final void Function(int) onChanged;
|
||||||
|
|
||||||
|
const ColorItem({
|
||||||
|
super.key,
|
||||||
|
required this.index,
|
||||||
|
required this.total,
|
||||||
|
required this.color,
|
||||||
|
required this.numericValue,
|
||||||
|
required this.selectedValue,
|
||||||
|
required this.onChanged
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: index == 0
|
||||||
|
? const EdgeInsets.only(top: 10, right: 10, bottom: 10)
|
||||||
|
: index == total-1
|
||||||
|
? const EdgeInsets.only(top: 10, bottom: 10, left: 10)
|
||||||
|
: const EdgeInsets.all(10),
|
||||||
|
child: Material(
|
||||||
|
borderRadius: BorderRadius.circular(50),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () => onChanged(numericValue),
|
||||||
|
borderRadius: BorderRadius.circular(50),
|
||||||
|
overlayColor: const MaterialStatePropertyAll(Colors.grey),
|
||||||
|
child: Container(
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: color,
|
||||||
|
borderRadius: BorderRadius.circular(50)
|
||||||
|
),
|
||||||
|
child: AnimatedOpacity(
|
||||||
|
opacity: numericValue == selectedValue ? 1 : 0,
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
child: Icon(
|
||||||
|
Icons.check,
|
||||||
|
size: 30,
|
||||||
|
color: color.computeLuminance() > 0.5 ? Colors.black : Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
156
lib/screens/settings/ui/customization/customization.dart
Normal file
156
lib/screens/settings/ui/customization/customization.dart
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
|
import 'package:linkdy/screens/settings/provider/customization.provider.dart';
|
||||||
|
import 'package:linkdy/screens/settings/ui/customization/color_item.dart';
|
||||||
|
import 'package:linkdy/screens/settings/ui/customization/theme_mode_button.dart';
|
||||||
|
import 'package:linkdy/utils/color_translation.dart';
|
||||||
|
import 'package:linkdy/widgets/custom_switch_list_tile.dart';
|
||||||
|
import 'package:linkdy/widgets/section_label.dart';
|
||||||
|
|
||||||
|
import 'package:linkdy/constants/colors.dart';
|
||||||
|
import 'package:linkdy/constants/enums.dart';
|
||||||
|
import 'package:linkdy/i18n/strings.g.dart';
|
||||||
|
import 'package:linkdy/providers/app_status_provider.dart';
|
||||||
|
|
||||||
|
class Customization extends ConsumerWidget {
|
||||||
|
const Customization({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final width = MediaQuery.of(context).size.width;
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(t.settings.customization.customization),
|
||||||
|
centerTitle: false,
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
child: ListView(
|
||||||
|
children: [
|
||||||
|
SectionLabel(
|
||||||
|
label: t.settings.customization.theme,
|
||||||
|
padding: const EdgeInsets.only(top: 10, left: 16, right: 16, bottom: 5),
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
CustomSwitchListTile(
|
||||||
|
value: ref.watch(appStatusProvider).selectedTheme == SelectedTheme.system ? true : false,
|
||||||
|
onChanged: (value) => ref
|
||||||
|
.read(appStatusProvider.notifier)
|
||||||
|
.setTheme(value == true ? SelectedTheme.system : SelectedTheme.light),
|
||||||
|
title: t.settings.customization.systemDefined,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
ThemeModeButton(
|
||||||
|
icon: Icons.light_mode,
|
||||||
|
value: 1,
|
||||||
|
selected: ref.watch(appStatusProvider).selectedTheme.index,
|
||||||
|
label: t.settings.customization.light,
|
||||||
|
onChanged: (value) => ref.read(appStatusProvider.notifier).setTheme(SelectedTheme.values[value]),
|
||||||
|
disabled: ref.watch(appStatusProvider).selectedTheme == SelectedTheme.system ? true : false,
|
||||||
|
),
|
||||||
|
ThemeModeButton(
|
||||||
|
icon: Icons.dark_mode,
|
||||||
|
value: 2,
|
||||||
|
selected: ref.watch(appStatusProvider).selectedTheme.index,
|
||||||
|
label: t.settings.customization.dark,
|
||||||
|
onChanged: (value) => ref.read(appStatusProvider.notifier).setTheme(SelectedTheme.values[value]),
|
||||||
|
disabled: ref.watch(appStatusProvider).selectedTheme == SelectedTheme.system ? true : false,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SectionLabel(
|
||||||
|
label: t.settings.customization.color,
|
||||||
|
padding: const EdgeInsets.only(top: 45, left: 16, right: 16, bottom: 5),
|
||||||
|
),
|
||||||
|
if (ref.watch(appStatusProvider).supportsDynamicTheme)
|
||||||
|
CustomSwitchListTile(
|
||||||
|
value: ref.watch(appStatusProvider).useDynamicTheme,
|
||||||
|
onChanged: ref.read(appStatusProvider.notifier).setUseDynamicTheme,
|
||||||
|
title: t.settings.customization.useDynamicTheme,
|
||||||
|
),
|
||||||
|
if (ref.watch(appStatusProvider).supportsDynamicTheme == false ||
|
||||||
|
(ref.watch(appStatusProvider).supportsDynamicTheme == true &&
|
||||||
|
ref.watch(appStatusProvider).useDynamicTheme == false))
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 8, left: 16, right: 16),
|
||||||
|
child: Scrollbar(
|
||||||
|
controller: ref.watch(customizationProvider).scrollController,
|
||||||
|
thumbVisibility: Platform.isMacOS || Platform.isLinux || Platform.isWindows,
|
||||||
|
interactive: Platform.isMacOS || Platform.isLinux || Platform.isWindows,
|
||||||
|
thickness: Platform.isMacOS || Platform.isLinux || Platform.isWindows ? 8 : 0,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 16),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: MediaQuery.of(context).size.width,
|
||||||
|
height: 70,
|
||||||
|
child: ListView.builder(
|
||||||
|
controller: ref.watch(customizationProvider).scrollController,
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
itemCount: colors.length,
|
||||||
|
padding: const EdgeInsets.all(0),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
if (index == 0) {
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
ColorItem(
|
||||||
|
index: index,
|
||||||
|
total: colors.length,
|
||||||
|
color: colors[index],
|
||||||
|
numericValue: index,
|
||||||
|
selectedValue: ref.watch(appStatusProvider).selectedColor,
|
||||||
|
onChanged: ref.read(appStatusProvider.notifier).setSelectedColor,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
width: 1,
|
||||||
|
height: 60,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey,
|
||||||
|
borderRadius: BorderRadius.circular(1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return ColorItem(
|
||||||
|
index: index,
|
||||||
|
total: colors.length,
|
||||||
|
color: colors[index],
|
||||||
|
numericValue: index,
|
||||||
|
selectedValue: ref.watch(appStatusProvider).selectedColor,
|
||||||
|
onChanged: ref.read(appStatusProvider.notifier).setSelectedColor,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: Text(
|
||||||
|
colorTranslation(ref.watch(appStatusProvider).selectedColor),
|
||||||
|
style: TextStyle(color: Theme.of(context).listTileTheme.iconColor, fontSize: 16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
88
lib/screens/settings/ui/customization/theme_mode_button.dart
Normal file
88
lib/screens/settings/ui/customization/theme_mode_button.dart
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class ThemeModeButton extends StatelessWidget {
|
||||||
|
final IconData icon;
|
||||||
|
final int value;
|
||||||
|
final int selected;
|
||||||
|
final String label;
|
||||||
|
final void Function(int) onChanged;
|
||||||
|
final bool? disabled;
|
||||||
|
|
||||||
|
const ThemeModeButton({
|
||||||
|
Key? key,
|
||||||
|
required this.icon,
|
||||||
|
required this.value,
|
||||||
|
required this.selected,
|
||||||
|
required this.label,
|
||||||
|
required this.onChanged,
|
||||||
|
this.disabled
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final Color greyBackgroundColor = Theme.of(context).brightness == Brightness.light
|
||||||
|
?const Color.fromRGBO(200, 200, 200, 1)
|
||||||
|
:const Color.fromRGBO(50, 50, 50, 1);
|
||||||
|
final Color greyIconColor = Theme.of(context).brightness == Brightness.light
|
||||||
|
? const Color.fromRGBO(130, 130, 130, 1)
|
||||||
|
: const Color.fromRGBO(100, 100, 100, 1);
|
||||||
|
|
||||||
|
return ElevatedButton(
|
||||||
|
onPressed: disabled == null || disabled == false
|
||||||
|
? () => onChanged(value)
|
||||||
|
: null,
|
||||||
|
style: ButtonStyle(
|
||||||
|
elevation: MaterialStateProperty.all(0),
|
||||||
|
shape: MaterialStateProperty.all(
|
||||||
|
RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(30),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
backgroundColor: MaterialStateProperty.all(
|
||||||
|
value == selected
|
||||||
|
? disabled == null || disabled == false
|
||||||
|
? Theme.of(context).colorScheme.primary
|
||||||
|
: greyBackgroundColor
|
||||||
|
: disabled == null || disabled == false
|
||||||
|
? Theme.of(context).colorScheme.surfaceVariant
|
||||||
|
: greyBackgroundColor,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
child: AnimatedContainer(
|
||||||
|
width: 118,
|
||||||
|
height: 150,
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
icon,
|
||||||
|
color: value == selected
|
||||||
|
? disabled == null || disabled == false
|
||||||
|
? Theme.of(context).colorScheme.primary.computeLuminance() > 0.5 ? Colors.black : Colors.white
|
||||||
|
: greyIconColor
|
||||||
|
: disabled == null || disabled == false
|
||||||
|
? Theme.of(context).colorScheme.primary
|
||||||
|
: greyIconColor,
|
||||||
|
size: 30,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
label,
|
||||||
|
style: TextStyle(
|
||||||
|
color: value == selected
|
||||||
|
? disabled == null || disabled == false
|
||||||
|
? Theme.of(context).colorScheme.primary.computeLuminance() > 0.5 ? Colors.black : Colors.white
|
||||||
|
: greyIconColor
|
||||||
|
: disabled == null || disabled == false
|
||||||
|
? Theme.of(context).colorScheme.primary
|
||||||
|
: greyIconColor,
|
||||||
|
fontSize: 18
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,16 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:linkdy/providers/router_provider.dart';
|
||||||
|
import 'package:linkdy/router/paths.dart';
|
||||||
|
|
||||||
|
import 'package:linkdy/widgets/section_label.dart';
|
||||||
|
import 'package:linkdy/widgets/custom_list_tile.dart';
|
||||||
|
|
||||||
|
import 'package:linkdy/providers/app_info_provider.dart';
|
||||||
|
import 'package:linkdy/utils/open_url.dart';
|
||||||
|
import 'package:linkdy/constants/strings.dart';
|
||||||
|
import 'package:linkdy/constants/urls.dart';
|
||||||
import 'package:linkdy/i18n/strings.g.dart';
|
import 'package:linkdy/i18n/strings.g.dart';
|
||||||
import 'package:linkdy/providers/api_client_provider.dart';
|
import 'package:linkdy/providers/api_client_provider.dart';
|
||||||
|
|
||||||
@@ -15,6 +25,18 @@ class Settings extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
body: ListView(
|
body: ListView(
|
||||||
children: [
|
children: [
|
||||||
|
SectionLabel(label: t.settings.appSettings),
|
||||||
|
CustomListTile(
|
||||||
|
icon: Icons.palette_rounded,
|
||||||
|
title: t.settings.customization.customization,
|
||||||
|
subtitle: t.settings.customizationDescription,
|
||||||
|
onTap: () => ref.read(routerProvider).push(RoutesPaths.customization),
|
||||||
|
),
|
||||||
|
CustomListTile(
|
||||||
|
icon: Icons.settings_rounded,
|
||||||
|
title: t.settings.generalSettings,
|
||||||
|
subtitle: t.settings.generalSettingsDescription,
|
||||||
|
),
|
||||||
FilledButton.icon(
|
FilledButton.icon(
|
||||||
onPressed: () => ref.read(apiClientProviderProvider.notifier).disconnectApiClient(),
|
onPressed: () => ref.read(apiClientProviderProvider.notifier).disconnectApiClient(),
|
||||||
icon: const Icon(Icons.clear_rounded),
|
icon: const Icon(Icons.clear_rounded),
|
||||||
@@ -22,6 +44,44 @@ class Settings extends ConsumerWidget {
|
|||||||
t.settings.disconnectFromServer,
|
t.settings.disconnectFromServer,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
SectionLabel(label: t.settings.aboutApp),
|
||||||
|
CustomListTile(
|
||||||
|
title: t.settings.appVersion,
|
||||||
|
subtitle: ref.watch(appInfoProvider).version,
|
||||||
|
),
|
||||||
|
CustomListTile(
|
||||||
|
title: t.settings.createdBy,
|
||||||
|
subtitle: Strings.createdBy,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(15),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
// if (Platform.isAndroid)
|
||||||
|
// IconButton(
|
||||||
|
// onPressed: () => openUrl(Urls.playStore),
|
||||||
|
// icon: SvgPicture.asset(
|
||||||
|
// 'assets/resources/google-play.svg',
|
||||||
|
// color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
|
// width: 30,
|
||||||
|
// height: 30,
|
||||||
|
// ),
|
||||||
|
// tooltip: t.settings.visitGooglePlay,
|
||||||
|
// ),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () => openUrl(Urls.gitHubRepo),
|
||||||
|
icon: SvgPicture.asset(
|
||||||
|
'assets/resources/github.svg',
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
|
width: 30,
|
||||||
|
height: 30,
|
||||||
|
),
|
||||||
|
tooltip: t.settings.visitGitHubRepo,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
22
lib/utils/color_translation.dart
Normal file
22
lib/utils/color_translation.dart
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:linkdy/i18n/strings.g.dart';
|
||||||
|
|
||||||
|
String colorTranslation(int index) {
|
||||||
|
// This indexes has to be in sync with colors array at constants/colors.dart
|
||||||
|
List<String> translations = [
|
||||||
|
"Linkding",
|
||||||
|
t.colors.red,
|
||||||
|
t.colors.green,
|
||||||
|
t.colors.blue,
|
||||||
|
t.colors.yellow,
|
||||||
|
t.colors.orange,
|
||||||
|
t.colors.brown,
|
||||||
|
t.colors.cyan,
|
||||||
|
t.colors.purple,
|
||||||
|
t.colors.pink,
|
||||||
|
t.colors.deepOrange,
|
||||||
|
t.colors.indigo,
|
||||||
|
];
|
||||||
|
return translations[index];
|
||||||
|
}
|
||||||
99
lib/widgets/custom_list_tile.dart
Normal file
99
lib/widgets/custom_list_tile.dart
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class CustomListTile extends StatelessWidget {
|
||||||
|
final String title;
|
||||||
|
final String? subtitle;
|
||||||
|
final Widget? subtitleWidget;
|
||||||
|
final void Function()? onTap;
|
||||||
|
final IconData? icon;
|
||||||
|
final Widget? trailing;
|
||||||
|
final EdgeInsets? padding;
|
||||||
|
final void Function()? onLongPress;
|
||||||
|
final bool? disabled;
|
||||||
|
final void Function(bool)? onHover;
|
||||||
|
final Color? color;
|
||||||
|
|
||||||
|
const CustomListTile({
|
||||||
|
Key? key,
|
||||||
|
required this.title,
|
||||||
|
this.subtitle,
|
||||||
|
this.subtitleWidget,
|
||||||
|
this.onTap,
|
||||||
|
this.icon,
|
||||||
|
this.trailing,
|
||||||
|
this.padding,
|
||||||
|
this.onLongPress,
|
||||||
|
this.disabled,
|
||||||
|
this.onHover,
|
||||||
|
this.color,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Material(
|
||||||
|
color: color ?? Colors.transparent,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: onTap,
|
||||||
|
onHover: onHover,
|
||||||
|
onLongPress: onLongPress,
|
||||||
|
child: Padding(
|
||||||
|
padding: padding ?? const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Flexible(
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
if (icon != null) ...[
|
||||||
|
Icon(
|
||||||
|
icon,
|
||||||
|
size: 24,
|
||||||
|
color: disabled == true
|
||||||
|
? Theme.of(context).colorScheme.onSurface.withOpacity(0.38)
|
||||||
|
: Theme.of(context).listTileTheme.iconColor,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
],
|
||||||
|
Flexible(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: disabled == true
|
||||||
|
? Theme.of(context).colorScheme.onSurface.withOpacity(0.38)
|
||||||
|
: Theme.of(context).colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (subtitle != null || subtitleWidget != null) ...[
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
if (subtitle == null && subtitleWidget != null) subtitleWidget!,
|
||||||
|
if (subtitle != null && subtitleWidget == null)
|
||||||
|
Text(
|
||||||
|
subtitle!,
|
||||||
|
style: TextStyle(
|
||||||
|
color: disabled == true
|
||||||
|
? Theme.of(context).colorScheme.onSurfaceVariant.withOpacity(0.38)
|
||||||
|
: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (trailing != null) ...[const SizedBox(width: 16), trailing!]
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
89
lib/widgets/custom_switch_list_tile.dart
Normal file
89
lib/widgets/custom_switch_list_tile.dart
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class CustomSwitchListTile extends StatelessWidget {
|
||||||
|
final bool value;
|
||||||
|
final void Function(bool) onChanged;
|
||||||
|
final String title;
|
||||||
|
final String? subtitle;
|
||||||
|
final bool? disabled;
|
||||||
|
final EdgeInsets? padding;
|
||||||
|
final IconData? leadingIcon;
|
||||||
|
|
||||||
|
const CustomSwitchListTile({
|
||||||
|
super.key,
|
||||||
|
required this.value,
|
||||||
|
required this.onChanged,
|
||||||
|
required this.title,
|
||||||
|
this.disabled,
|
||||||
|
this.subtitle,
|
||||||
|
this.padding,
|
||||||
|
this.leadingIcon,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: disabled != null && disabled == true
|
||||||
|
? null
|
||||||
|
: () => onChanged(!value),
|
||||||
|
child: Padding(
|
||||||
|
padding: padding ?? const EdgeInsets.only(
|
||||||
|
top: 12, left: 16, right: 18, bottom: 16
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
if (leadingIcon != null) ...[
|
||||||
|
Icon(
|
||||||
|
leadingIcon,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
],
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: disabled != null && disabled == true
|
||||||
|
? Theme.of(context).colorScheme.onSurface.withOpacity(0.38)
|
||||||
|
: Theme.of(context).colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (subtitle != null) ... [
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
SizedBox(
|
||||||
|
width: MediaQuery.of(context).size.width-110,
|
||||||
|
child: Text(
|
||||||
|
subtitle!,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: disabled != null && disabled == true
|
||||||
|
? Theme.of(context).listTileTheme.textColor!.withOpacity(0.38)
|
||||||
|
: Theme.of(context).listTileTheme.textColor
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Switch(
|
||||||
|
value: value,
|
||||||
|
onChanged: disabled != null && disabled == true
|
||||||
|
? null
|
||||||
|
: onChanged,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import Foundation
|
|||||||
|
|
||||||
import dynamic_color
|
import dynamic_color
|
||||||
import flutter_inappwebview_macos
|
import flutter_inappwebview_macos
|
||||||
|
import package_info_plus
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
import share_plus
|
import share_plus
|
||||||
import shared_preferences_foundation
|
import shared_preferences_foundation
|
||||||
@@ -15,6 +16,7 @@ import url_launcher_macos
|
|||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin"))
|
DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin"))
|
||||||
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
|
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
|
||||||
|
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
|
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
|
||||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
|
|||||||
16
pubspec.lock
16
pubspec.lock
@@ -661,6 +661,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.0"
|
||||||
|
package_info_plus:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: package_info_plus
|
||||||
|
sha256: "88bc797f44a94814f2213db1c9bd5badebafdfb8290ca9f78d4b9ee2a3db4d79"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.0.1"
|
||||||
|
package_info_plus_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: package_info_plus_platform_interface
|
||||||
|
sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ dependencies:
|
|||||||
flutter_custom_tabs: ^2.0.0+1
|
flutter_custom_tabs: ^2.0.0+1
|
||||||
flutter_inappwebview: ^6.0.0
|
flutter_inappwebview: ^6.0.0
|
||||||
share_plus: ^7.2.2
|
share_plus: ^7.2.2
|
||||||
|
package_info_plus: ^5.0.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
build_runner: ^2.4.8
|
build_runner: ^2.4.8
|
||||||
|
|||||||
Reference in New Issue
Block a user