Improved webview

This commit is contained in:
Juan Gilsanz Polo
2024-02-22 22:11:41 +01:00
parent 83fe30408f
commit 8d85b80b09
15 changed files with 465 additions and 430 deletions

View File

@@ -5,6 +5,9 @@
android:label="Linkdy" android:label="Linkdy"
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher">
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"

View File

@@ -4,9 +4,9 @@
/// To regenerate, run: `dart run slang` /// To regenerate, run: `dart run slang`
/// ///
/// Locales: 2 /// Locales: 2
/// Strings: 54 (27 per locale) /// Strings: 58 (29 per locale)
/// ///
/// Built on 2024-02-22 at 17:42 UTC /// Built on 2024-02-22 at 21:08 UTC
// coverage:ignore-file // coverage:ignore-file
// ignore_for_file: type=lint // ignore_for_file: type=lint
@@ -28,17 +28,12 @@ enum AppLocale with BaseAppLocale<AppLocale, Translations> {
en(languageCode: 'en', build: Translations.build), en(languageCode: 'en', build: Translations.build),
es(languageCode: 'es', build: _StringsEs.build); es(languageCode: 'es', build: _StringsEs.build);
const AppLocale( const AppLocale({required this.languageCode, this.scriptCode, this.countryCode, required this.build}); // ignore: unused_element
{required this.languageCode, this.scriptCode, this.countryCode, required this.build}); // ignore: unused_element
@override @override final String languageCode;
final String languageCode; @override final String? scriptCode;
@override @override final String? countryCode;
final String? scriptCode; @override final TranslationBuilder<AppLocale, Translations> build;
@override
final String? countryCode;
@override
final TranslationBuilder<AppLocale, Translations> build;
/// Gets current instance managed by [LocaleSettings]. /// Gets current instance managed by [LocaleSettings].
Translations get translations => LocaleSettings.instance.translationMap[this]!; Translations get translations => LocaleSettings.instance.translationMap[this]!;
@@ -73,8 +68,7 @@ Translations get t => LocaleSettings.instance.currentTranslations;
class TranslationProvider extends BaseTranslationProvider<AppLocale, Translations> { class TranslationProvider extends BaseTranslationProvider<AppLocale, Translations> {
TranslationProvider({required super.child}) : super(settings: LocaleSettings.instance); TranslationProvider({required super.child}) : super(settings: LocaleSettings.instance);
static InheritedLocaleData<AppLocale, Translations> of(BuildContext context) => static InheritedLocaleData<AppLocale, Translations> of(BuildContext context) => InheritedLocaleData.of<AppLocale, Translations>(context);
InheritedLocaleData.of<AppLocale, Translations>(context);
} }
/// Method B shorthand via [BuildContext] extension method. /// Method B shorthand via [BuildContext] extension method.
@@ -95,18 +89,12 @@ class LocaleSettings extends BaseFlutterLocaleSettings<AppLocale, Translations>
// static aliases (checkout base methods for documentation) // static aliases (checkout base methods for documentation)
static AppLocale get currentLocale => instance.currentLocale; static AppLocale get currentLocale => instance.currentLocale;
static Stream<AppLocale> getLocaleStream() => instance.getLocaleStream(); static Stream<AppLocale> getLocaleStream() => instance.getLocaleStream();
static AppLocale setLocale(AppLocale locale, {bool? listenToDeviceLocale = false}) => static AppLocale setLocale(AppLocale locale, {bool? listenToDeviceLocale = false}) => instance.setLocale(locale, listenToDeviceLocale: listenToDeviceLocale);
instance.setLocale(locale, listenToDeviceLocale: listenToDeviceLocale); static AppLocale setLocaleRaw(String rawLocale, {bool? listenToDeviceLocale = false}) => instance.setLocaleRaw(rawLocale, listenToDeviceLocale: listenToDeviceLocale);
static AppLocale setLocaleRaw(String rawLocale, {bool? listenToDeviceLocale = false}) =>
instance.setLocaleRaw(rawLocale, listenToDeviceLocale: listenToDeviceLocale);
static AppLocale useDeviceLocale() => instance.useDeviceLocale(); static AppLocale useDeviceLocale() => instance.useDeviceLocale();
@Deprecated('Use [AppLocaleUtils.supportedLocales]') @Deprecated('Use [AppLocaleUtils.supportedLocales]') static List<Locale> get supportedLocales => instance.supportedLocales;
static List<Locale> get supportedLocales => instance.supportedLocales; @Deprecated('Use [AppLocaleUtils.supportedLocalesRaw]') static List<String> get supportedLocalesRaw => instance.supportedLocalesRaw;
@Deprecated('Use [AppLocaleUtils.supportedLocalesRaw]') static void setPluralResolver({String? language, AppLocale? locale, PluralResolver? cardinalResolver, PluralResolver? ordinalResolver}) => instance.setPluralResolver(
static List<String> get supportedLocalesRaw => instance.supportedLocalesRaw;
static void setPluralResolver(
{String? language, AppLocale? locale, PluralResolver? cardinalResolver, PluralResolver? ordinalResolver}) =>
instance.setPluralResolver(
language: language, language: language,
locale: locale, locale: locale,
cardinalResolver: cardinalResolver, cardinalResolver: cardinalResolver,
@@ -122,8 +110,7 @@ class AppLocaleUtils extends BaseAppLocaleUtils<AppLocale, Translations> {
// static aliases (checkout base methods for documentation) // static aliases (checkout base methods for documentation)
static AppLocale parse(String rawLocale) => instance.parse(rawLocale); static AppLocale parse(String rawLocale) => instance.parse(rawLocale);
static AppLocale parseLocaleParts({required String languageCode, String? scriptCode, String? countryCode}) => static AppLocale parseLocaleParts({required String languageCode, String? scriptCode, String? countryCode}) => instance.parseLocaleParts(languageCode: languageCode, scriptCode: scriptCode, countryCode: countryCode);
instance.parseLocaleParts(languageCode: languageCode, scriptCode: scriptCode, countryCode: countryCode);
static AppLocale findDeviceLocale() => instance.findDeviceLocale(); static AppLocale findDeviceLocale() => instance.findDeviceLocale();
static List<Locale> get supportedLocales => instance.supportedLocales; static List<Locale> get supportedLocales => instance.supportedLocales;
static List<String> get supportedLocalesRaw => instance.supportedLocalesRaw; static List<String> get supportedLocalesRaw => instance.supportedLocalesRaw;
@@ -153,11 +140,10 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
} }
/// Metadata for the translations of <en>. /// Metadata for the translations of <en>.
@override @override final TranslationMetadata<AppLocale, Translations> $meta;
final TranslationMetadata<AppLocale, Translations> $meta;
/// Access flat map /// Access flat map
dynamic operator [](String key) => $meta.getTranslation(key); dynamic operator[](String key) => $meta.getTranslation(key);
late final Translations _root = this; // ignore: unused_field late final Translations _root = this; // ignore: unused_field
@@ -166,6 +152,7 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
late final _StringsLinksEn links = _StringsLinksEn._(_root); late final _StringsLinksEn links = _StringsLinksEn._(_root);
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);
} }
// Path: onboarding // Path: onboarding
@@ -181,8 +168,7 @@ class _StringsOnboardingEn {
String get next => 'Next'; String get next => 'Next';
String get previous => 'Previous'; String get previous => 'Previous';
String get serverRequired => 'Servidor requerido'; String get serverRequired => 'Servidor requerido';
String get serverRequiredDescription => String get serverRequiredDescription => 'Linkdy it\'s not an standalone app, it requires the Linkding server to work.\nIn order to use this application, you must deploy Linkding on your home server, VPS or any other computer.';
'Linkdy it\'s not an standalone app, it requires the Linkding server to work.\nIn order to use this application, you must deploy Linkding on your home server, VPS or any other computer.';
String get installationInstructions => 'Check the installation instructions on the official GitHub repository.'; String get installationInstructions => 'Check the installation instructions on the official GitHub repository.';
String get serverRunningConfirmation => 'I confirm that I have an instance of the Linkding server already running.'; String get serverRunningConfirmation => 'I confirm that I have an instance of the Linkding server already running.';
String get createConnection => 'Create a connection'; String get createConnection => 'Create a connection';
@@ -231,6 +217,17 @@ class _StringsSettingsEn {
String get disconnectFromServer => 'Disconnect from server'; String get disconnectFromServer => 'Disconnect from server';
} }
// Path: webview
class _StringsWebviewEn {
_StringsWebviewEn._(this._root);
final Translations _root; // ignore: unused_field
// Translations
String get goBack => 'Go back';
String get goForward => 'Go forward';
}
// Path: links.dates // Path: links.dates
class _StringsLinksDatesEn { class _StringsLinksDatesEn {
_StringsLinksDatesEn._(this._root); _StringsLinksDatesEn._(this._root);
@@ -258,134 +255,103 @@ class _StringsEs implements Translations {
} }
/// Metadata for the translations of <es>. /// Metadata for the translations of <es>.
@override @override final TranslationMetadata<AppLocale, Translations> $meta;
final TranslationMetadata<AppLocale, Translations> $meta;
/// Access flat map /// Access flat map
@override @override dynamic operator[](String key) => $meta.getTranslation(key);
dynamic operator [](String key) => $meta.getTranslation(key);
@override @override late final _StringsEs _root = this; // ignore: unused_field
late final _StringsEs _root = this; // ignore: unused_field
// Translations // Translations
@override @override late final _StringsOnboardingEs onboarding = _StringsOnboardingEs._(_root);
late final _StringsOnboardingEs onboarding = _StringsOnboardingEs._(_root); @override late final _StringsLinksEs links = _StringsLinksEs._(_root);
@override @override late final _StringsSearchEs search = _StringsSearchEs._(_root);
late final _StringsLinksEs links = _StringsLinksEs._(_root); @override late final _StringsSettingsEs settings = _StringsSettingsEs._(_root);
@override @override late final _StringsWebviewEs webview = _StringsWebviewEs._(_root);
late final _StringsSearchEs search = _StringsSearchEs._(_root);
@override
late final _StringsSettingsEs settings = _StringsSettingsEs._(_root);
} }
// Path: onboarding // Path: onboarding
class _StringsOnboardingEs implements _StringsOnboardingEn { class _StringsOnboardingEs implements _StringsOnboardingEn {
_StringsOnboardingEs._(this._root); _StringsOnboardingEs._(this._root);
@override @override final _StringsEs _root; // ignore: unused_field
final _StringsEs _root; // ignore: unused_field
// Translations // Translations
@override @override String get title => 'Bienvenido a Linkdy';
String get title => 'Bienvenido a Linkdy'; @override String get subtitle => 'Una aplicación para gestionar tus enlaces favoritos.';
@override @override String get start => 'Comenzar';
String get subtitle => 'Una aplicación para gestionar tus enlaces favoritos.'; @override String get next => 'Siguiente';
@override @override String get previous => 'Anterior';
String get start => 'Comenzar'; @override String get serverRequired => 'Servidor requerido';
@override @override String get serverRequiredDescription => 'Linkdy no es una aplicación independiente, requiere el servidor Linkding para funcionar.\nPara utilizar esta aplicación, debe instalar Linkding en su servidor doméstico, VPS o cualquier otro ordenador.';
String get next => 'Siguiente'; @override String get installationInstructions => 'Mira las instrucciones de instalación en el repositorio oficial en GitHub.';
@override @override String get serverRunningConfirmation => 'Confirmo que tengo una instancia del servidor Linkding ya en funcionamiento.';
String get previous => 'Anterior'; @override String get createConnection => 'Crear una conexión';
@override @override String get createConnectionSubtitle => 'Introduce todos los detalles requeridos para crear una conexión con el servidor';
String get serverRequired => 'Servidor requerido'; @override String get ipAddressOrDomain => 'Dirección IP o dominio';
@override @override String get port => 'Puerto';
String get serverRequiredDescription => @override String get token => 'Token';
'Linkdy no es una aplicación independiente, requiere el servidor Linkding para funcionar.\nPara utilizar esta aplicación, debe instalar Linkding en su servidor doméstico, VPS o cualquier otro ordenador.'; @override String get required => 'Requerido';
@override @override String get serverDetails => 'Detalles del servidor';
String get installationInstructions => 'Mira las instrucciones de instalación en el repositorio oficial en GitHub.'; @override String get authentication => 'Autenticación';
@override @override String get testConnectionUrl => 'Probar URL de conexión';
String get serverRunningConfirmation => @override String get connect => 'Conectar';
'Confirmo que tengo una instancia del servidor Linkding ya en funcionamiento.'; @override String get connecting => 'Conectando...';
@override @override String get cannotConnectToServer => 'No se puede conectar con el servidor.';
String get createConnection => 'Crear una conexión';
@override
String get createConnectionSubtitle =>
'Introduce todos los detalles requeridos para crear una conexión con el servidor';
@override
String get ipAddressOrDomain => 'Dirección IP o dominio';
@override
String get port => 'Puerto';
@override
String get token => 'Token';
@override
String get required => 'Requerido';
@override
String get serverDetails => 'Detalles del servidor';
@override
String get authentication => 'Autenticación';
@override
String get testConnectionUrl => 'Probar URL de conexión';
@override
String get connect => 'Conectar';
@override
String get connecting => 'Conectando...';
@override
String get cannotConnectToServer => 'No se puede conectar con el servidor.';
} }
// Path: links // Path: links
class _StringsLinksEs implements _StringsLinksEn { class _StringsLinksEs implements _StringsLinksEn {
_StringsLinksEs._(this._root); _StringsLinksEs._(this._root);
@override @override final _StringsEs _root; // ignore: unused_field
final _StringsEs _root; // ignore: unused_field
// Translations // Translations
@override @override String get links => 'Enlaces';
String get links => 'Enlaces'; @override late final _StringsLinksDatesEs dates = _StringsLinksDatesEs._(_root);
@override
late final _StringsLinksDatesEs dates = _StringsLinksDatesEs._(_root);
} }
// Path: search // Path: search
class _StringsSearchEs implements _StringsSearchEn { class _StringsSearchEs implements _StringsSearchEn {
_StringsSearchEs._(this._root); _StringsSearchEs._(this._root);
@override @override final _StringsEs _root; // ignore: unused_field
final _StringsEs _root; // ignore: unused_field
// Translations // Translations
@override @override String get search => 'Buscar';
String get search => 'Buscar';
} }
// Path: settings // Path: settings
class _StringsSettingsEs implements _StringsSettingsEn { class _StringsSettingsEs implements _StringsSettingsEn {
_StringsSettingsEs._(this._root); _StringsSettingsEs._(this._root);
@override @override final _StringsEs _root; // ignore: unused_field
final _StringsEs _root; // ignore: unused_field
// Translations // Translations
@override @override String get settings => 'Ajustes';
String get settings => 'Ajustes'; @override String get disconnectFromServer => 'Desconectar del servidor';
@override }
String get disconnectFromServer => 'Desconectar del servidor';
// Path: webview
class _StringsWebviewEs implements _StringsWebviewEn {
_StringsWebviewEs._(this._root);
@override final _StringsEs _root; // ignore: unused_field
// Translations
@override String get goBack => 'Ir atrás';
@override String get goForward => 'Ir adelante';
} }
// Path: links.dates // Path: links.dates
class _StringsLinksDatesEs implements _StringsLinksDatesEn { class _StringsLinksDatesEs implements _StringsLinksDatesEn {
_StringsLinksDatesEs._(this._root); _StringsLinksDatesEs._(this._root);
@override @override final _StringsEs _root; // ignore: unused_field
final _StringsEs _root; // ignore: unused_field
// Translations // Translations
@override @override String todayAt({required Object time}) => 'Hoy, ${time}';
String todayAt({required Object time}) => 'Hoy, ${time}'; @override String yesterdayAt({required Object time}) => 'Ayer, ${time}';
@override
String yesterdayAt({required Object time}) => 'Ayer, ${time}';
} }
/// Flat map(s) containing all translations. /// Flat map(s) containing all translations.
@@ -394,62 +360,36 @@ class _StringsLinksDatesEs implements _StringsLinksDatesEn {
extension on Translations { extension on Translations {
dynamic _flatMapFunction(String path) { dynamic _flatMapFunction(String path) {
switch (path) { switch (path) {
case 'onboarding.title': case 'onboarding.title': return 'Welcome to Linkdy';
return 'Welcome to Linkdy'; case 'onboarding.subtitle': return 'An application to manage your bookmarks.';
case 'onboarding.subtitle': case 'onboarding.start': return 'Start';
return 'An application to manage your bookmarks.'; case 'onboarding.next': return 'Next';
case 'onboarding.start': case 'onboarding.previous': return 'Previous';
return 'Start'; case 'onboarding.serverRequired': return 'Servidor requerido';
case 'onboarding.next': case 'onboarding.serverRequiredDescription': return 'Linkdy it\'s not an standalone app, it requires the Linkding server to work.\nIn order to use this application, you must deploy Linkding on your home server, VPS or any other computer.';
return 'Next'; case 'onboarding.installationInstructions': return 'Check the installation instructions on the official GitHub repository.';
case 'onboarding.previous': case 'onboarding.serverRunningConfirmation': return 'I confirm that I have an instance of the Linkding server already running.';
return 'Previous'; case 'onboarding.createConnection': return 'Create a connection';
case 'onboarding.serverRequired': case 'onboarding.createConnectionSubtitle': return 'Enter all the required details to create a connection to your server.';
return 'Servidor requerido'; case 'onboarding.ipAddressOrDomain': return 'IP address or domain';
case 'onboarding.serverRequiredDescription': case 'onboarding.port': return 'Port';
return 'Linkdy it\'s not an standalone app, it requires the Linkding server to work.\nIn order to use this application, you must deploy Linkding on your home server, VPS or any other computer.'; case 'onboarding.token': return 'Token';
case 'onboarding.installationInstructions': case 'onboarding.required': return 'Required';
return 'Check the installation instructions on the official GitHub repository.'; case 'onboarding.serverDetails': return 'Server details';
case 'onboarding.serverRunningConfirmation': case 'onboarding.authentication': return 'Authentication';
return 'I confirm that I have an instance of the Linkding server already running.'; case 'onboarding.testConnectionUrl': return 'Test connection url';
case 'onboarding.createConnection': case 'onboarding.connect': return 'Connect';
return 'Create a connection'; case 'onboarding.connecting': return 'Connecting...';
case 'onboarding.createConnectionSubtitle': case 'onboarding.cannotConnectToServer': return 'Cannot connect to the server.';
return 'Enter all the required details to create a connection to your server.'; case 'links.links': return 'Links';
case 'onboarding.ipAddressOrDomain': case 'links.dates.todayAt': return ({required Object time}) => 'Today, ${time}';
return 'IP address or domain'; case 'links.dates.yesterdayAt': return ({required Object time}) => 'Yesterday, ${time}';
case 'onboarding.port': case 'search.search': return 'Search';
return 'Port'; case 'settings.settings': return 'Settings';
case 'onboarding.token': case 'settings.disconnectFromServer': return 'Disconnect from server';
return 'Token'; case 'webview.goBack': return 'Go back';
case 'onboarding.required': case 'webview.goForward': return 'Go forward';
return 'Required'; default: return null;
case 'onboarding.serverDetails':
return 'Server details';
case 'onboarding.authentication':
return 'Authentication';
case 'onboarding.testConnectionUrl':
return 'Test connection url';
case 'onboarding.connect':
return 'Connect';
case 'onboarding.connecting':
return 'Connecting...';
case 'onboarding.cannotConnectToServer':
return 'Cannot connect to the server.';
case 'links.links':
return 'Links';
case 'links.dates.todayAt':
return ({required Object time}) => 'Today, ${time}';
case 'links.dates.yesterdayAt':
return ({required Object time}) => 'Yesterday, ${time}';
case 'search.search':
return 'Search';
case 'settings.settings':
return 'Settings';
case 'settings.disconnectFromServer':
return 'Disconnect from server';
default:
return null;
} }
} }
} }
@@ -457,62 +397,36 @@ extension on Translations {
extension on _StringsEs { extension on _StringsEs {
dynamic _flatMapFunction(String path) { dynamic _flatMapFunction(String path) {
switch (path) { switch (path) {
case 'onboarding.title': case 'onboarding.title': return 'Bienvenido a Linkdy';
return 'Bienvenido a Linkdy'; case 'onboarding.subtitle': return 'Una aplicación para gestionar tus enlaces favoritos.';
case 'onboarding.subtitle': case 'onboarding.start': return 'Comenzar';
return 'Una aplicación para gestionar tus enlaces favoritos.'; case 'onboarding.next': return 'Siguiente';
case 'onboarding.start': case 'onboarding.previous': return 'Anterior';
return 'Comenzar'; case 'onboarding.serverRequired': return 'Servidor requerido';
case 'onboarding.next': case 'onboarding.serverRequiredDescription': return 'Linkdy no es una aplicación independiente, requiere el servidor Linkding para funcionar.\nPara utilizar esta aplicación, debe instalar Linkding en su servidor doméstico, VPS o cualquier otro ordenador.';
return 'Siguiente'; case 'onboarding.installationInstructions': return 'Mira las instrucciones de instalación en el repositorio oficial en GitHub.';
case 'onboarding.previous': case 'onboarding.serverRunningConfirmation': return 'Confirmo que tengo una instancia del servidor Linkding ya en funcionamiento.';
return 'Anterior'; case 'onboarding.createConnection': return 'Crear una conexión';
case 'onboarding.serverRequired': case 'onboarding.createConnectionSubtitle': return 'Introduce todos los detalles requeridos para crear una conexión con el servidor';
return 'Servidor requerido'; case 'onboarding.ipAddressOrDomain': return 'Dirección IP o dominio';
case 'onboarding.serverRequiredDescription': case 'onboarding.port': return 'Puerto';
return 'Linkdy no es una aplicación independiente, requiere el servidor Linkding para funcionar.\nPara utilizar esta aplicación, debe instalar Linkding en su servidor doméstico, VPS o cualquier otro ordenador.'; case 'onboarding.token': return 'Token';
case 'onboarding.installationInstructions': case 'onboarding.required': return 'Requerido';
return 'Mira las instrucciones de instalación en el repositorio oficial en GitHub.'; case 'onboarding.serverDetails': return 'Detalles del servidor';
case 'onboarding.serverRunningConfirmation': case 'onboarding.authentication': return 'Autenticación';
return 'Confirmo que tengo una instancia del servidor Linkding ya en funcionamiento.'; case 'onboarding.testConnectionUrl': return 'Probar URL de conexión';
case 'onboarding.createConnection': case 'onboarding.connect': return 'Conectar';
return 'Crear una conexión'; case 'onboarding.connecting': return 'Conectando...';
case 'onboarding.createConnectionSubtitle': case 'onboarding.cannotConnectToServer': return 'No se puede conectar con el servidor.';
return 'Introduce todos los detalles requeridos para crear una conexión con el servidor'; case 'links.links': return 'Enlaces';
case 'onboarding.ipAddressOrDomain': case 'links.dates.todayAt': return ({required Object time}) => 'Hoy, ${time}';
return 'Dirección IP o dominio'; case 'links.dates.yesterdayAt': return ({required Object time}) => 'Ayer, ${time}';
case 'onboarding.port': case 'search.search': return 'Buscar';
return 'Puerto'; case 'settings.settings': return 'Ajustes';
case 'onboarding.token': case 'settings.disconnectFromServer': return 'Desconectar del servidor';
return 'Token'; case 'webview.goBack': return 'Ir atrás';
case 'onboarding.required': case 'webview.goForward': return 'Ir adelante';
return 'Requerido'; default: return null;
case 'onboarding.serverDetails':
return 'Detalles del servidor';
case 'onboarding.authentication':
return 'Autenticación';
case 'onboarding.testConnectionUrl':
return 'Probar URL de conexión';
case 'onboarding.connect':
return 'Conectar';
case 'onboarding.connecting':
return 'Conectando...';
case 'onboarding.cannotConnectToServer':
return 'No se puede conectar con el servidor.';
case 'links.links':
return 'Enlaces';
case 'links.dates.todayAt':
return ({required Object time}) => 'Hoy, ${time}';
case 'links.dates.yesterdayAt':
return ({required Object time}) => 'Ayer, ${time}';
case 'search.search':
return 'Buscar';
case 'settings.settings':
return 'Ajustes';
case 'settings.disconnectFromServer':
return 'Desconectar del servidor';
default:
return null;
} }
} }
} }

View File

@@ -35,5 +35,9 @@
"settings": { "settings": {
"settings": "Settings", "settings": "Settings",
"disconnectFromServer": "Disconnect from server" "disconnectFromServer": "Disconnect from server"
},
"webview": {
"goBack": "Go back",
"goForward": "Go forward"
} }
} }

View File

@@ -35,5 +35,9 @@
"settings": { "settings": {
"settings": "Ajustes", "settings": "Ajustes",
"disconnectFromServer": "Desconectar del servidor" "disconnectFromServer": "Desconectar del servidor"
},
"webview": {
"goBack": "Ir atrás",
"goForward": "Ir adelante"
} }
} }

View File

@@ -21,6 +21,10 @@ final List<RouteBase> appRoutes = [
path: RoutesPaths.onboarding, path: RoutesPaths.onboarding,
builder: (context, state) => const Onboarding(), builder: (context, state) => const Onboarding(),
), ),
GoRoute(
path: RoutesPaths.webview,
builder: (context, state) => WebView(bookmark: state.extra as Bookmark),
),
StatefulShellRoute.indexedStack( StatefulShellRoute.indexedStack(
builder: (context, state, navigationShell) => Layout( builder: (context, state, navigationShell) => Layout(
navigationShell: navigationShell, navigationShell: navigationShell,
@@ -34,10 +38,6 @@ final List<RouteBase> appRoutes = [
path: RoutesPaths.links, path: RoutesPaths.links,
builder: (context, state) => const Links(), builder: (context, state) => const Links(),
), ),
GoRoute(
path: RoutesPaths.webview,
builder: (context, state) => WebView(bookmark: state.extra as Bookmark),
),
], ],
), ),
StatefulShellBranch( StatefulShellBranch(

View File

@@ -2,11 +2,11 @@ import 'package:flutter/material.dart';
class OnboardingModel { class OnboardingModel {
final PageController pageController; final PageController pageController;
final bool confirmServerRunning; bool confirmServerRunning;
OnboardingModel({ OnboardingModel({
required this.pageController, required this.pageController,
required this.confirmServerRunning, this.confirmServerRunning = false,
}); });
OnboardingModel toggleConfirmServerRunning(bool newValue) => OnboardingModel( OnboardingModel toggleConfirmServerRunning(bool newValue) => OnboardingModel(

View File

@@ -30,6 +30,7 @@ class Onboarding extends _$Onboarding {
} }
void confirmServerRunning() { void confirmServerRunning() {
state = state.toggleConfirmServerRunning(!state.confirmServerRunning); state.confirmServerRunning = !state.confirmServerRunning;
ref.notifyListeners();
} }
} }

View File

@@ -6,7 +6,7 @@ part of 'onboarding.provider.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$onboardingHash() => r'5c876d53acbca92ab15630516099700609aa4f89'; String _$onboardingHash() => r'06f4c2d233d6babdd1d8fef05e5a6285e19ec453';
/// See also [Onboarding]. /// See also [Onboarding].
@ProviderFor(Onboarding) @ProviderFor(Onboarding)

View File

@@ -1,9 +1,15 @@
import 'package:webview_flutter/webview_flutter.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart';
class WebViewModel { class WebViewModel {
final WebViewController webViewController; InAppWebViewController? inAppWebViewController;
int loadProgress;
bool canGoBack;
bool canGoForward;
WebViewModel({ WebViewModel({
required this.webViewController, this.inAppWebViewController,
this.loadProgress = 0,
this.canGoBack = false,
this.canGoForward = false,
}); });
} }

View File

@@ -1,5 +1,5 @@
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:linkdy/screens/webview/model/webview.model.dart'; import 'package:linkdy/screens/webview/model/webview.model.dart';
@@ -9,25 +9,25 @@ part 'webview.provider.g.dart';
class WebView extends _$WebView { class WebView extends _$WebView {
@override @override
WebViewModel build() { WebViewModel build() {
return WebViewModel( return WebViewModel();
webViewController: WebViewController(
onPermissionRequest: (request) => request.deny(),
)
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(
NavigationDelegate(
onProgress: (int progress) {
// Update loading bar.
},
onPageStarted: (String url) {},
onPageFinished: (String url) {},
onWebResourceError: (WebResourceError error) {},
),
),
);
} }
void initialize(String url) { void initializeController(InAppWebViewController controller) {
state.webViewController.loadRequest(Uri.parse(url)); state.inAppWebViewController = controller;
}
void setLoadProgress(int progress) {
state.loadProgress = progress;
ref.notifyListeners();
}
void setCanGoBack(bool value) {
state.canGoBack = value;
ref.notifyListeners();
}
void setCanGoForward(bool value) {
state.canGoForward = value;
ref.notifyListeners();
} }
} }

View File

@@ -6,7 +6,7 @@ part of 'webview.provider.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$webViewHash() => r'9eb114ec97e04b92aa1e2ec9fc8948b1443c948c'; String _$webViewHash() => r'55d815688ade5764e1b2b4c862f81df45d98ae3b';
/// See also [WebView]. /// See also [WebView].
@ProviderFor(WebView) @ProviderFor(WebView)

View File

@@ -1,9 +1,11 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:linkdy/models/data/bookmarks.dart';
import 'package:linkdy/screens/webview/provider/webview.provider.dart'; import 'package:linkdy/screens/webview/provider/webview.provider.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:linkdy/models/data/bookmarks.dart';
import 'package:linkdy/i18n/strings.g.dart';
class WebView extends ConsumerWidget { class WebView extends ConsumerWidget {
final Bookmark bookmark; final Bookmark bookmark;
@@ -15,17 +17,92 @@ class WebView extends ConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
WidgetsBinding.instance.addPostFrameCallback((_) {
ref.read(webViewProvider.notifier).initialize(bookmark.url!);
});
final webViewController = ref.watch(webViewProvider).webViewController;
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(bookmark.title != "" ? bookmark.title! : bookmark.websiteTitle!), elevation: 3,
title: Column(
children: [
Text(
bookmark.title != "" ? bookmark.title! : bookmark.websiteTitle!,
style: const TextStyle(fontSize: 14),
),
const SizedBox(height: 4),
Text(
bookmark.url!,
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
],
),
bottom: PreferredSize(
preferredSize: const Size(double.maxFinite, 0),
child: ref.watch(webViewProvider).loadProgress < 100
? LinearProgressIndicator(
value: ref.watch(webViewProvider).loadProgress.toDouble(),
)
: const SizedBox(
height: 4,
),
),
),
body: SafeArea(
child: Column(
children: [
Expanded(
child: InAppWebView(
initialUrlRequest: URLRequest(url: WebUri.uri(Uri.parse(bookmark.url!))),
onWebViewCreated: (controller) {
ref.read(webViewProvider).inAppWebViewController = controller;
},
onPermissionRequest: (controller, request) async {
return PermissionResponse(
resources: request.resources,
action: PermissionResponseAction.DENY,
);
},
onProgressChanged: (controller, progress) {
ref.read(webViewProvider.notifier).setLoadProgress(progress);
},
initialSettings: InAppWebViewSettings(
allowContentAccess: false,
allowFileAccess: false,
applePayAPIEnabled: false,
cacheEnabled: false,
isInspectable: false,
),
onUpdateVisitedHistory: (controller, url, androidIsReload) {
controller.canGoBack().then((value) => ref.read(webViewProvider.notifier).setCanGoBack(value));
controller.canGoForward().then((value) => ref.read(webViewProvider.notifier).setCanGoForward(value));
},
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
IconButton(
onPressed: ref.watch(webViewProvider).canGoBack == true
? () => ref.watch(webViewProvider).inAppWebViewController?.goBack()
: null,
icon: const Icon(Icons.arrow_back_rounded),
tooltip: t.webview.goForward,
),
const SizedBox(width: 8),
IconButton(
onPressed: ref.watch(webViewProvider).canGoForward == true
? () => ref.watch(webViewProvider).inAppWebViewController?.goForward()
: null,
icon: const Icon(Icons.arrow_forward_rounded),
tooltip: t.webview.goForward,
),
],
),
),
],
),
), ),
body: webViewController != null ? WebViewWidget(controller: ref.watch(webViewProvider).webViewController!) : null,
); );
} }
} }

View File

@@ -6,11 +6,13 @@ import FlutterMacOS
import Foundation import Foundation
import dynamic_color import dynamic_color
import flutter_inappwebview_macos
import shared_preferences_foundation import shared_preferences_foundation
import url_launcher_macos 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"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
} }

View File

@@ -358,6 +358,62 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.0" version: "2.0.0"
flutter_inappwebview:
dependency: "direct main"
description:
name: flutter_inappwebview
sha256: "3e9a443a18ecef966fb930c3a76ca5ab6a7aafc0c7b5e14a4a850cf107b09959"
url: "https://pub.dev"
source: hosted
version: "6.0.0"
flutter_inappwebview_android:
dependency: transitive
description:
name: flutter_inappwebview_android
sha256: d247f6ed417f1f8c364612fa05a2ecba7f775c8d0c044c1d3b9ee33a6515c421
url: "https://pub.dev"
source: hosted
version: "1.0.13"
flutter_inappwebview_internal_annotations:
dependency: transitive
description:
name: flutter_inappwebview_internal_annotations
sha256: "5f80fd30e208ddded7dbbcd0d569e7995f9f63d45ea3f548d8dd4c0b473fb4c8"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
flutter_inappwebview_ios:
dependency: transitive
description:
name: flutter_inappwebview_ios
sha256: f363577208b97b10b319cd0c428555cd8493e88b468019a8c5635a0e4312bd0f
url: "https://pub.dev"
source: hosted
version: "1.0.13"
flutter_inappwebview_macos:
dependency: transitive
description:
name: flutter_inappwebview_macos
sha256: b55b9e506c549ce88e26580351d2c71d54f4825901666bd6cfa4be9415bb2636
url: "https://pub.dev"
source: hosted
version: "1.0.11"
flutter_inappwebview_platform_interface:
dependency: transitive
description:
name: flutter_inappwebview_platform_interface
sha256: "545fd4c25a07d2775f7d5af05a979b2cac4fbf79393b0a7f5d33ba39ba4f6187"
url: "https://pub.dev"
source: hosted
version: "1.0.10"
flutter_inappwebview_web:
dependency: transitive
description:
name: flutter_inappwebview_web
sha256: d8c680abfb6fec71609a700199635d38a744df0febd5544c5a020bd73de8ee07
url: "https://pub.dev"
source: hosted
version: "1.0.8"
flutter_lints: flutter_lints:
dependency: "direct dev" dependency: "direct dev"
description: description:
@@ -375,10 +431,10 @@ packages:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: flutter_native_splash name: flutter_native_splash
sha256: "45e2c0986d749c070509e03d6c7ad6c8bd1f7b1dad7d11dd8750a5e4fe3e2c0b" sha256: "558f10070f03ee71f850a78f7136ab239a67636a294a44a06b6b7345178edb1e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.11" version: "2.3.10"
flutter_riverpod: flutter_riverpod:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -513,10 +569,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: js name: js
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.1" version: "0.6.7"
json2yaml: json2yaml:
dependency: transitive dependency: transitive
description: description:
@@ -1082,38 +1138,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.0" version: "2.4.0"
webview_flutter:
dependency: "direct main"
description:
name: webview_flutter
sha256: "25e1b6e839e8cbfbd708abc6f85ed09d1727e24e08e08c6b8590d7c65c9a8932"
url: "https://pub.dev"
source: hosted
version: "4.7.0"
webview_flutter_android:
dependency: transitive
description:
name: webview_flutter_android
sha256: "3e5f4e9d818086b0d01a66fb1ff9cc72ab0cc58c71980e3d3661c5685ea0efb0"
url: "https://pub.dev"
source: hosted
version: "3.15.0"
webview_flutter_platform_interface:
dependency: transitive
description:
name: webview_flutter_platform_interface
sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d
url: "https://pub.dev"
source: hosted
version: "2.10.0"
webview_flutter_wkwebview:
dependency: transitive
description:
name: webview_flutter_wkwebview
sha256: "9bf168bccdf179ce90450b5f37e36fe263f591c9338828d6bf09b6f8d0f57f86"
url: "https://pub.dev"
source: hosted
version: "3.12.0"
win32: win32:
dependency: transitive dependency: transitive
description: description:
@@ -1148,4 +1172,4 @@ packages:
version: "3.1.2" version: "3.1.2"
sdks: sdks:
dart: ">=3.2.6 <4.0.0" dart: ">=3.2.6 <4.0.0"
flutter: ">=3.16.6" flutter: ">=3.16.0"

View File

@@ -47,7 +47,7 @@ dependencies:
slang_flutter: ^3.29.0 slang_flutter: ^3.29.0
flutter_svg: ^2.0.9 flutter_svg: ^2.0.9
flutter_custom_tabs: ^2.0.0+1 flutter_custom_tabs: ^2.0.0+1
webview_flutter: ^4.7.0 flutter_inappwebview: ^6.0.0
dev_dependencies: dev_dependencies:
build_runner: ^2.4.8 build_runner: ^2.4.8