From ad2fe114d75e13e64e73f3c7e0b476ba74a3f482 Mon Sep 17 00:00:00 2001 From: Sergiy <125032334+sergd88@users.noreply.github.com> Date: Sat, 4 Nov 2023 02:14:25 +0200 Subject: [PATCH 01/31] i18n: Polishing translations for English and Russian languages (#866) --- app/assets/i18n/strings.i18n.json | 8 ++++---- app/assets/i18n/strings_ru.i18n.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/assets/i18n/strings.i18n.json b/app/assets/i18n/strings.i18n.json index 30c7fe43752..ca004e4ca01 100644 --- a/app/assets/i18n/strings.i18n.json +++ b/app/assets/i18n/strings.i18n.json @@ -45,7 +45,7 @@ "infoBox": { "ip": "IP:", "port": "Port:", - "alias": "Alias:" + "alias": "Device name:" } }, "sendTab": { @@ -114,7 +114,7 @@ "title": "Network", "needRestart": "Restart the server to apply the settings!", "server": "Server", - "alias": "Alias", + "alias": "Device name", "deviceType": "Device type", "deviceModel": "Device model", "port": "Port", @@ -328,8 +328,8 @@ }, "favoriteEditDialog": { "titleAdd": "Add to favorites", - "titleEdit": "Adjustment", - "name": "Alias", + "titleEdit": "Settings", + "name": "Device name", "auto": "(auto)", "ip": "IP Address", "port": "Port" diff --git a/app/assets/i18n/strings_ru.i18n.json b/app/assets/i18n/strings_ru.i18n.json index 37b27ca1faa..2b81b874a27 100644 --- a/app/assets/i18n/strings_ru.i18n.json +++ b/app/assets/i18n/strings_ru.i18n.json @@ -258,7 +258,7 @@ }, "favoriteEditDialog": { "titleAdd": "Добавить в избранное", - "titleEdit": "Настройка", + "titleEdit": "Настройки", "name": "Имя устройства", "auto": "(автоматически)", "ip": "IP-адрес", From 3092571654d6e231911db11f4701bca7b4907185 Mon Sep 17 00:00:00 2001 From: Tien Do Nam Date: Sun, 5 Nov 2023 15:53:07 +0100 Subject: [PATCH 02/31] feat: make project work with Xcode 15 --- app/ios/Podfile.lock | 2 +- app/ios/Runner.xcodeproj/project.pbxproj | 6 +++--- app/pubspec.lock | 12 ++++++------ app/pubspec.yaml | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/ios/Podfile.lock b/app/ios/Podfile.lock index ea404767c72..c8f09f0d289 100644 --- a/app/ios/Podfile.lock +++ b/app/ios/Podfile.lock @@ -164,7 +164,7 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/wakelock_plus/ios" SPEC CHECKSUMS: - connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a + connectivity_plus: bf0076dd84a130856aa636df1c71ccaff908fa1d device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6 DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 diff --git a/app/ios/Runner.xcodeproj/project.pbxproj b/app/ios/Runner.xcodeproj/project.pbxproj index 3f8146f5d24..ecb1355531e 100644 --- a/app/ios/Runner.xcodeproj/project.pbxproj +++ b/app/ios/Runner.xcodeproj/project.pbxproj @@ -214,14 +214,14 @@ buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( 9C4064819D92C3F1614A347F /* [CP] Check Pods Manifest.lock */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 28D9F9AD29638D5E0028B96E /* Embed Foundation Extensions */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 38A5402B0B18EA0E910C92D1 /* [CP] Embed Pods Frameworks */, - 28D9F9AD29638D5E0028B96E /* Embed Foundation Extensions */, ); buildRules = ( ); @@ -362,7 +362,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n"; }; 9C4064819D92C3F1614A347F /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; diff --git a/app/pubspec.lock b/app/pubspec.lock index 6d7db310a05..4f35415b851 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -196,10 +196,10 @@ packages: dependency: "direct main" description: name: connectivity_plus - sha256: "77a180d6938f78ca7d2382d2240eb626c0f6a735d0bfdce227d8ffb80f95c48b" + sha256: b502a681ba415272ecc41400bd04fe543ed1a62632137dc84d25a91e7746f55f url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "5.0.1" connectivity_plus_platform_interface: dependency: transitive description: @@ -1089,18 +1089,18 @@ packages: dependency: transitive description: name: refena - sha256: "8c1a5f818084886e4f9a38b0ce1f1c636992ac5fae7645f22c2236aa8982f439" + sha256: bb28bf3144381f6bb859763e695eb602affc4289dbd67470c747b9ea6f57b0a8 url: "https://pub.dev" source: hosted - version: "0.40.3" + version: "0.43.0" refena_flutter: dependency: "direct main" description: name: refena_flutter - sha256: "86291df3817a4962aced6de7de537e7e51bbb8acea41934122c798ea1d12693c" + sha256: "097018e8691daa894789a8dd7bcd47618c6f25c86b9a4c26c93d7d954868990e" url: "https://pub.dev" source: hosted - version: "0.40.4" + version: "0.43.0" refena_inspector: dependency: "direct dev" description: diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 0490d70a10f..7f0bf70f27e 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: collection: ^1.17.2 # allow newer versions, so it can compile with newer Flutter versions common: path: ../common - connectivity_plus: 4.0.2 + connectivity_plus: 5.0.1 dart_mappable: 3.3.1 desktop_drop: 0.4.4 device_apps: 2.2.0 @@ -43,7 +43,7 @@ dependencies: path_provider: 2.1.1 permission_handler: 11.0.1 pretty_qr_code: 2.0.3 - refena_flutter: 0.40.4 + refena_flutter: 0.43.0 refena_inspector_client: 0.8.0 routerino: 0.8.0 screen_retriever: 0.1.9 From 8617c6364f6b6e79fa02af714c34c6caca5c1f0c Mon Sep 17 00:00:00 2001 From: Tien Do Nam Date: Sun, 5 Nov 2023 15:53:18 +0100 Subject: [PATCH 03/31] i18n: regenerate --- app/lib/gen/strings_en.g.dart | 8 ++++---- app/lib/gen/strings_ru.g.dart | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/lib/gen/strings_en.g.dart b/app/lib/gen/strings_en.g.dart index f36109aefed..2ed479e9f7b 100644 --- a/app/lib/gen/strings_en.g.dart +++ b/app/lib/gen/strings_en.g.dart @@ -466,7 +466,7 @@ class _StringsReceiveTabInfoBoxEn { // Translations String get ip => 'IP:'; String get port => 'Port:'; - String get alias => 'Alias:'; + String get alias => 'Device name:'; } // Path: sendTab.selection @@ -554,7 +554,7 @@ class _StringsSettingsTabNetworkEn { String get title => 'Network'; String get needRestart => 'Restart the server to apply the settings!'; String get server => 'Server'; - String get alias => 'Alias'; + String get alias => 'Device name'; String get deviceType => 'Device type'; String get deviceModel => 'Device model'; String get port => 'Port'; @@ -710,8 +710,8 @@ class _StringsDialogsFavoriteEditDialogEn { // Translations String get titleAdd => 'Add to favorites'; - String get titleEdit => 'Adjustment'; - String get name => 'Alias'; + String get titleEdit => 'Settings'; + String get name => 'Device name'; String get auto => '(auto)'; String get ip => 'IP Address'; String get port => 'Port'; diff --git a/app/lib/gen/strings_ru.g.dart b/app/lib/gen/strings_ru.g.dart index c4182242811..be4c3ae70e0 100644 --- a/app/lib/gen/strings_ru.g.dart +++ b/app/lib/gen/strings_ru.g.dart @@ -640,7 +640,7 @@ class _StringsDialogsFavoriteEditDialogRu extends _StringsDialogsFavoriteEditDia // Translations @override String get titleAdd => 'Добавить в избранное'; - @override String get titleEdit => 'Настройка'; + @override String get titleEdit => 'Настройки'; @override String get name => 'Имя устройства'; @override String get auto => '(автоматически)'; @override String get ip => 'IP-адрес'; From 7171a96567c393e29da99c075d885c9ab9375125 Mon Sep 17 00:00:00 2001 From: Tien Do Nam Date: Sun, 5 Nov 2023 16:16:46 +0100 Subject: [PATCH 04/31] feat: improve logging --- app/lib/model/log_entry.dart | 5 +++++ .../model/persistence/stored_security_context.dart | 5 +++++ app/lib/pages/tabs/receive_tab_vm.dart | 4 ++-- app/lib/pages/tabs/settings_tab_controller.dart | 8 ++++---- app/lib/provider/app_arguments_provider.dart | 2 +- app/lib/provider/logging/http_logs_provider.dart | 11 ++++++----- app/lib/provider/network/server/server_provider.dart | 8 ++++---- app/lib/provider/settings_provider.dart | 8 ++++---- app/lib/provider/tv_provider.dart | 2 +- app/lib/widget/dialogs/address_input_dialog.dart | 7 ++++--- app/pubspec.lock | 8 ++++---- app/pubspec.yaml | 2 +- 12 files changed, 41 insertions(+), 29 deletions(-) diff --git a/app/lib/model/log_entry.dart b/app/lib/model/log_entry.dart index 953d3451518..683079db8b2 100644 --- a/app/lib/model/log_entry.dart +++ b/app/lib/model/log_entry.dart @@ -11,4 +11,9 @@ class LogEntry with LogEntryMappable { required this.timestamp, required this.log, }); + + @override + String toString() { + return 'LogEntry(timestamp: $timestamp, log: $log)'; + } } diff --git a/app/lib/model/persistence/stored_security_context.dart b/app/lib/model/persistence/stored_security_context.dart index 8653c85f619..cfdebd0fc83 100644 --- a/app/lib/model/persistence/stored_security_context.dart +++ b/app/lib/model/persistence/stored_security_context.dart @@ -17,4 +17,9 @@ class StoredSecurityContext with StoredSecurityContextMappable { }); static const fromJson = StoredSecurityContextMapper.fromJson; + + @override + String toString() { + return 'StoredSecurityContext(, , , )'; + } } diff --git a/app/lib/pages/tabs/receive_tab_vm.dart b/app/lib/pages/tabs/receive_tab_vm.dart index d04336435f8..940c699ebd2 100644 --- a/app/lib/pages/tabs/receive_tab_vm.dart +++ b/app/lib/pages/tabs/receive_tab_vm.dart @@ -8,11 +8,11 @@ import 'package:localsend_app/widget/dialogs/quick_save_notice.dart'; import 'package:refena_flutter/refena_flutter.dart'; /// Whether the advanced network info is shown -final _showAdvancedProvider = StateProvider((ref) => false); +final _showAdvancedProvider = StateProvider((ref) => false, debugLabel: '_showAdvancedProvider'); /// Whether the history button is shown /// This extra boolean is needed to delay the animation -final _showHistoryButtonProvider = StateProvider((ref) => true); +final _showHistoryButtonProvider = StateProvider((ref) => true, debugLabel: '_showHistoryButtonProvider'); class ReceiveTabVm { final String aliasSettings; diff --git a/app/lib/pages/tabs/settings_tab_controller.dart b/app/lib/pages/tabs/settings_tab_controller.dart index 3bd8c0e8af6..4ce32118c86 100644 --- a/app/lib/pages/tabs/settings_tab_controller.dart +++ b/app/lib/pages/tabs/settings_tab_controller.dart @@ -28,14 +28,14 @@ final settingsTabControllerProvider = ReduxProvider { - final SettingsNotifier _settingsService; - final ServerNotifier _serverService; + final SettingsService _settingsService; + final ServerService _serverService; final DeviceInfoResult _initialDeviceInfo; final bool _supportsDynamicColors; SettingsTabController({ - required SettingsNotifier settingsService, - required ServerNotifier serverNotifier, + required SettingsService settingsService, + required ServerService serverNotifier, required DeviceInfoResult initialDeviceInfo, required bool supportsDynamicColors, }) : _settingsService = settingsService, diff --git a/app/lib/provider/app_arguments_provider.dart b/app/lib/provider/app_arguments_provider.dart index a69dfcd130e..5e88d60d649 100644 --- a/app/lib/provider/app_arguments_provider.dart +++ b/app/lib/provider/app_arguments_provider.dart @@ -1,4 +1,4 @@ import 'package:refena_flutter/refena_flutter.dart'; /// Contains the arguments with which the app was started. -final appArgumentsProvider = Provider((ref) => []); +final appArgumentsProvider = Provider((ref) => [], debugLabel: 'appArgumentsProvider'); diff --git a/app/lib/provider/logging/http_logs_provider.dart b/app/lib/provider/logging/http_logs_provider.dart index 16215888ad6..debacf45df9 100644 --- a/app/lib/provider/logging/http_logs_provider.dart +++ b/app/lib/provider/logging/http_logs_provider.dart @@ -5,13 +5,11 @@ import 'package:refena_flutter/refena_flutter.dart'; final _logger = Logger('HTTP'); /// Contains the discovery logs for debugging purposes. -final httpLogsProvider = NotifierProvider>((ref) { - return HttpLogsNotifier(); +final httpLogsProvider = NotifierProvider>((ref) { + return HttpLogsService(); }); -class HttpLogsNotifier extends Notifier> { - HttpLogsNotifier(); - +class HttpLogsService extends Notifier> { @override List init() { return []; @@ -28,4 +26,7 @@ class HttpLogsNotifier extends Notifier> { void clear() { state = []; } + + @override + String describeState(List state) => '${state.length} logs'; } diff --git a/app/lib/provider/network/server/server_provider.dart b/app/lib/provider/network/server/server_provider.dart index 2ca03bf1a9e..5211ddbd84f 100644 --- a/app/lib/provider/network/server/server_provider.dart +++ b/app/lib/provider/network/server/server_provider.dart @@ -21,11 +21,11 @@ final _logger = Logger('Server'); /// It is a singleton provider, so only one server can be running at a time. /// The server state is null if the server is not running. /// The server can receive files (since v1) and send files (since v2). -final serverProvider = NotifierProvider((ref) { - return ServerNotifier(); +final serverProvider = NotifierProvider((ref) { + return ServerService(); }); -class ServerNotifier extends Notifier { +class ServerService extends Notifier { late final _serverUtils = ServerUtils( refFunc: () => ref, getState: () => state!, @@ -36,7 +36,7 @@ class ServerNotifier extends Notifier { late final _receiveController = ReceiveController(_serverUtils); late final _sendController = SendController(_serverUtils); - ServerNotifier(); + ServerService(); @override ServerState? init() { diff --git a/app/lib/provider/settings_provider.dart b/app/lib/provider/settings_provider.dart index 7f4cc47e0ff..8f84524bbe7 100644 --- a/app/lib/provider/settings_provider.dart +++ b/app/lib/provider/settings_provider.dart @@ -7,14 +7,14 @@ import 'package:localsend_app/model/state/settings_state.dart'; import 'package:localsend_app/provider/persistence_provider.dart'; import 'package:refena_flutter/refena_flutter.dart'; -final settingsProvider = NotifierProvider((ref) { - return SettingsNotifier(); +final settingsProvider = NotifierProvider((ref) { + return SettingsService(); }); -class SettingsNotifier extends Notifier { +class SettingsService extends Notifier { late PersistenceService _service; - SettingsNotifier(); + SettingsService(); @override SettingsState init() { diff --git a/app/lib/provider/tv_provider.dart b/app/lib/provider/tv_provider.dart index 25df522214d..0d84915aa67 100644 --- a/app/lib/provider/tv_provider.dart +++ b/app/lib/provider/tv_provider.dart @@ -3,7 +3,7 @@ import 'package:flutter/services.dart'; import 'package:localsend_app/util/native/platform_check.dart'; import 'package:refena_flutter/refena_flutter.dart'; -final tvProvider = Provider((_) => throw Exception('tvProvider not initialized')); +final tvProvider = Provider((_) => throw Exception('tvProvider not initialized'), debugLabel: 'tvProvider'); /// Returns true, if this device is a TV. /// Currently, only supports Android TV. diff --git a/app/lib/widget/dialogs/address_input_dialog.dart b/app/lib/widget/dialogs/address_input_dialog.dart index e312947f4a8..8959381efce 100644 --- a/app/lib/widget/dialogs/address_input_dialog.dart +++ b/app/lib/widget/dialogs/address_input_dialog.dart @@ -65,15 +65,16 @@ class _AddressInputDialogState extends State with Refena { bool found = false; - await results.forEach((device) { - if (!found && device != null) { + await for (final device in results) { + if (device != null) { found = true; if (mounted) { ref.notifier(lastDevicesProvider).addDevice(device); context.pop(device); } + break; } - }); + } if (!found && mounted) { setState(() { diff --git a/app/pubspec.lock b/app/pubspec.lock index 4f35415b851..d2c4994a0a0 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -1089,18 +1089,18 @@ packages: dependency: transitive description: name: refena - sha256: bb28bf3144381f6bb859763e695eb602affc4289dbd67470c747b9ea6f57b0a8 + sha256: "23ab9f06da5e2e258c2a43da3b932065b40f1d6dbbd65f050497abe4d93ec6f5" url: "https://pub.dev" source: hosted - version: "0.43.0" + version: "0.44.0" refena_flutter: dependency: "direct main" description: name: refena_flutter - sha256: "097018e8691daa894789a8dd7bcd47618c6f25c86b9a4c26c93d7d954868990e" + sha256: d82dd38539ffe925294b9fec9b2b3d286b00ce0491edeed53dbecd423f80d917 url: "https://pub.dev" source: hosted - version: "0.43.0" + version: "0.44.0" refena_inspector: dependency: "direct dev" description: diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 7f0bf70f27e..6aa997f2ff9 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -43,7 +43,7 @@ dependencies: path_provider: 2.1.1 permission_handler: 11.0.1 pretty_qr_code: 2.0.3 - refena_flutter: 0.43.0 + refena_flutter: 0.44.0 refena_inspector_client: 0.8.0 routerino: 0.8.0 screen_retriever: 0.1.9 From 58a2c5bac9a786b5fc0091db6ada7ab08ea9b1cb Mon Sep 17 00:00:00 2001 From: Tien Do Nam Date: Sun, 5 Nov 2023 23:08:19 +0100 Subject: [PATCH 05/31] fix: invalid use of ref.watch --- app/lib/pages/receive_page.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/pages/receive_page.dart b/app/lib/pages/receive_page.dart index 2a18d822248..7e19da787f1 100644 --- a/app/lib/pages/receive_page.dart +++ b/app/lib/pages/receive_page.dart @@ -37,7 +37,7 @@ class _ReceivePageState extends State with Refena { } Future _init() async { - final receiveSession = ref.watch(serverProvider)?.session; + final receiveSession = ref.read(serverProvider)?.session; if (receiveSession == null) { return; } From 2dde1e57090d0859e297c024631e1076c9e1b1f0 Mon Sep 17 00:00:00 2001 From: Tien Do Nam Date: Tue, 7 Nov 2023 14:49:25 +0100 Subject: [PATCH 06/31] deps: bump refena to 1.0.0 --- app/pubspec.lock | 16 ++++++++-------- app/pubspec.yaml | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/pubspec.lock b/app/pubspec.lock index d2c4994a0a0..9d3ccd701fd 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -1089,34 +1089,34 @@ packages: dependency: transitive description: name: refena - sha256: "23ab9f06da5e2e258c2a43da3b932065b40f1d6dbbd65f050497abe4d93ec6f5" + sha256: "2d810cc535a081fa4d2183fd9e172821db5ae19d65bed2d7fd543670b2c5cab3" url: "https://pub.dev" source: hosted - version: "0.44.0" + version: "1.0.0" refena_flutter: dependency: "direct main" description: name: refena_flutter - sha256: d82dd38539ffe925294b9fec9b2b3d286b00ce0491edeed53dbecd423f80d917 + sha256: "236b150a1e0098a1bbe521299121df55fea6962cf6e034181c4f2e21c1a91f54" url: "https://pub.dev" source: hosted - version: "0.44.0" + version: "1.0.0" refena_inspector: dependency: "direct dev" description: name: refena_inspector - sha256: be1292f944ec3eadbff5bdb93969d8e3ff7b2538a9cd6ce39e2a1b08b5f82352 + sha256: "03b41ce4ebb1b6f15d6e975d062fa97f045ece8ebdbb7979ee8b6716cdb5080e" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "1.0.0" refena_inspector_client: dependency: "direct main" description: name: refena_inspector_client - sha256: "411cd55af364d6654f1ef117fe08e626c22b6fe514c28d9f22742eba2f80c551" + sha256: "4fbbd54c04ac5382e20081ad0d625abfcfddb395a0dabb3e331de62419cd6ef5" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "1.0.0" routerino: dependency: "direct main" description: diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 6aa997f2ff9..a0e27db89d7 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -43,8 +43,8 @@ dependencies: path_provider: 2.1.1 permission_handler: 11.0.1 pretty_qr_code: 2.0.3 - refena_flutter: 0.44.0 - refena_inspector_client: 0.8.0 + refena_flutter: 1.0.0 + refena_inspector_client: 1.0.0 routerino: 0.8.0 screen_retriever: 0.1.9 share_handler: 0.0.19 @@ -74,7 +74,7 @@ dev_dependencies: flutter_gen_runner: 5.3.2 flutter_lints: 2.0.3 msix: 3.16.4 - refena_inspector: 0.8.0 + refena_inspector: 1.0.0 slang_build_runner: 3.25.0 slang_gpt: 0.10.0 test: ^1.24.3 From ffa7e449ce08d677007b07d0a4d843109c20192b Mon Sep 17 00:00:00 2001 From: nibras shami Date: Wed, 8 Nov 2023 05:29:20 +0300 Subject: [PATCH 07/31] i18n: Update Arabic Translation (#874) * Update `_missing_translations_ar.json` * Fix Typo --- app/assets/i18n/_missing_translations_ar.json | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/app/assets/i18n/_missing_translations_ar.json b/app/assets/i18n/_missing_translations_ar.json index 664bef995b2..3f88e5682d3 100644 --- a/app/assets/i18n/_missing_translations_ar.json +++ b/app/assets/i18n/_missing_translations_ar.json @@ -4,12 +4,12 @@ "After editing this file, you can run 'dart run slang apply --locale=ar' to quickly apply the newly added translations." ], "general": { - "delete": "Delete", - "noItemInClipboard": "No item in Clipboard" + "delete": "حذف", + "noItemInClipboard": "لا توجد عناصر في الحافظة" }, "sendTab": { "picker": { - "clipboard": "Paste" + "clipboard": "لصق" } }, "settingsTab": { @@ -21,25 +21,25 @@ }, "dialogs": { "favoriteDialog": { - "title": "Favorites", - "noFavorites": "No favorites devices yet.", - "addFavorite": "Add" + "title": "المفضلة", + "noFavorites": "لا توجد أجهزة مفضلة بعد.", + "addFavorite": "إضافة" }, "favoriteDeleteDialog": { - "title": "Delete from favorites", - "content": "Do you really want to delete from favorites \"{name}\"?" + "title": "حذف من المفضلة", + "content": "هل ترغب حقًا في حذف \"{name}\" من قائمة المفضلة؟" }, "favoriteEditDialog": { - "titleAdd": "Add to favorites", - "titleEdit": "Adjustment", - "name": "Alias", - "auto": "(auto)", - "ip": "IP Address", + "titleAdd": "إضافة إلى المفضلة", + "titleEdit": "تعديل", + "name": "الاسم", + "auto": "(تلقائي)", + "ip": "عنوان IP", "port": "Port" }, "historyClearDialog": { - "title": "Clear history", - "content": "Do you really want to delete the entire history?" + "title": "محو السجل", + "content": "هل ترغب حقًا في محو السجل بالكامل؟" } } } From ed127c97e1c6c22b02c1bfc95cc50950a2cdb29c Mon Sep 17 00:00:00 2001 From: "Chandara H. Wei" <117574639+nidexingg@users.noreply.github.com> Date: Thu, 9 Nov 2023 01:45:20 +0700 Subject: [PATCH 08/31] Update CONTRIBUTING.md (#878) --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 249792dd481..f3f506e7457 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -46,6 +46,7 @@ Thanks to all translators! | Hungarian | @gidano | | Hebrew | @ShlomoCode | | Japanese | @soya-daizu | +| Khmer | Chandara H. Wei (@nidexingg) | | Korean | @mgmix | | Russian | Sergiy (@sergd88) | | Ukrainian | Sergiy (@sergd88) | From c5bf4d678688ef9fd2a6031d55f80b38d6c90e95 Mon Sep 17 00:00:00 2001 From: Bryan James Date: Sat, 11 Nov 2023 04:22:01 +0800 Subject: [PATCH 09/31] i18n: Fixed grammar and spelling issues on fil-PH translation (#880) --- app/assets/i18n/strings_fil-PH.i18n.json | 48 ++++++++++++------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/app/assets/i18n/strings_fil-PH.i18n.json b/app/assets/i18n/strings_fil-PH.i18n.json index 0de98622b50..ec8f630a687 100644 --- a/app/assets/i18n/strings_fil-PH.i18n.json +++ b/app/assets/i18n/strings_fil-PH.i18n.json @@ -13,7 +13,7 @@ "copy": "Kopyahin", "copiedToClipboard": "Kopyahin sa Clipboard", "decline": "Tanggihan", - "done": "Tapusin", + "done": "Tapos Na", "delete": "Tanggalin", "edit": "Baguhin", "error": "Error", @@ -63,7 +63,7 @@ "app": "App", "clipboard": "Paste" }, - "shareIntentInfo": "Maaring gamitin ang \"Share\" feature sa iyong mobile device para sa mas madaling pagpili ng mga files.", + "shareIntentInfo": "Maaring gamitin ang \"Share\" feature sa iyong mobile device para sa mas madaling pagpili ng mga file.", "nearbyDevices": "Malalapit na mga device", "thisDevice": "Ang Device na Ito", "scan": "Maghanap ng mga device", @@ -96,9 +96,9 @@ "languageOptions": { "system": "System" }, - "saveWindowPlacement": "Quit: I-Save ang window placement", + "saveWindowPlacement": "Quit: I-save ang window placement", "minimizeToTray": "Quit: Paliitin sa Tray/Menu Bar", - "launchAtStartup": "I-Autostart pagkatapos mag-login", + "launchAtStartup": "I-autostart pagkatapos mag-login", "launchMinimized": "Autostart: I-start nang nakatago", "animations": "Animations" }, @@ -107,12 +107,12 @@ "quickSave": "@:general.quickSave", "destination": "Patutunguhan", "downloads": "(Downloads)", - "saveToGallery": "I-Save ang media sa gallery", - "saveToHistory": "I-Save sa history" + "saveToGallery": "I-save ang media sa gallery", + "saveToHistory": "I-save sa history" }, "network": { "title": "Network", - "needRestart": "I-Restart ang server para i-apply ang settings!", + "needRestart": "I-restart ang server para i-apply ang settings!", "server": "Server", "alias": "Alias", "deviceType": "Device type", @@ -131,12 +131,12 @@ "solution": "Solusyon:", "fixButton": "Awtomatikong ayusin", "firewall": { - "symptom": "Ang app na ito ay nakakapag-padala ng mga file sa ibang devices ngunit ang ibang devices ay hindi makapag-padala sa device na ito.", - "solution": "Ito ay kadalasang isyu sa firewall. Maari mo maayos sa pamamagitan nang pag-allow ng mga incoming connections (UDP at TCP) sa port {port}.", + "symptom": "Ang app na ito ay nakakapagpadala ng mga file sa ibang devices ngunit ang ibang devices ay hindi makapagpadala sa device na ito.", + "solution": "Ito ay kadalasang isyu sa firewall. Maari mong maayos ito sa pamamagitan nang pag-allow ng mga incoming connections (UDP at TCP) sa port {port}.", "openFirewall": "Buksan ang Firewall" }, "noConnection": { - "symptom": "Ang dalawa o higit pang devices ay hindi mo discover ang isa't isa o hindi makapag-share ng files.", + "symptom": "Ang dalawa o higit pang devices ay hindi mo discover ang isa't isa o hindi makapag-share ng mga file.", "solution": "Ang problema ay nangyayari sa dalawang device? Mangyaring siguraduhin na ang dalawang device ay nasa parehas na wifi network at mayroong parehas na configuration (port, multicast address, encryption). Maaring ang wifi ay hindi pinahihintulutan and komunikasyon sa pagitan nang mga participants. Sa ganitong pangyayari, ang option na ito ay dapat i-enable sa router." } }, @@ -166,8 +166,8 @@ "other": "ay gustong magpadala sa iyo ng {n} na mga file." }, "subTitleMessage": "ay nagpadala sa iyo ng mensahe:", - "subTitleLink": "ay nagpadala sa iyo ng likn:", - "canceled": "Ang sender ay nag-kansela ng request." + "subTitleLink": "ay nagpadala sa iyo ng link:", + "canceled": "Ang sender ay nagkansela ng request." }, "receiveOptionsPage": { "title": "Options", @@ -184,10 +184,10 @@ "progressPage": { "titleSending": "Nagpapadala ng mga file", "titleReceiving": "Tumatanggap ng mga file", - "savedToGallery": "Naka-Save sa Photos", + "savedToGallery": "Naka-save sa Photos", "total": { "title": { - "sending": "Kabuuang progress ({time})", + "sending": "Kabuuang progreso ({time})", "finishedError": "Natapos nang may error", "canceledSender": "Kinansela ng sender", "canceledReceiver": "Kinansela ng receiver" @@ -198,10 +198,10 @@ } }, "webSharePage": { - "title": "I-Share gamit ang link", + "title": "I-share gamit ang link", "loading": "Binubuksan ang server...", "stopping": "Ihinihinto ang server...", - "error": "May nangyaring error habang buksan ang server.", + "error": "May nangyaring error habang binubuksan ang server.", "openLink": { "one": "Buksan ang link na ito sa browser:", "other": "Buksan ang isa sa mga link na ito sa browser:" @@ -312,7 +312,7 @@ }, "encryptionDisabledNotice": { "title": "Ang encryption ay naka-disable", - "content": "Ang communication ay nangyayari ngayon gamit ang unencrypted HTTP protocol. Para gamitin ang HTTPS, muling i-enable ang encryption." + "content": "Ang communication ngayon ay nangyayari gamit ang unencrypted HTTP protocol. Para gamitin ang HTTPS, muling i-enable ang encryption." }, "errorDialog": { "title": "@:general.error" @@ -352,11 +352,11 @@ }, "localNetworkUnauthorized": { "title": "@:dialogs.noPermission.title", - "description": "Hindi makikita ng LocalSend ang ibang devices hangga't hindi nabibigyan ng permission para mag scan sa lokal na network. Mangyaring bigyan ito ng permission sa settings.", + "description": "Hindi makikita ng LocalSend ang ibang devices hangga't hindi nabibigyan ng permission para mag-scan sa lokal na network. Mangyaring bigyan ito ng permission sa settings.", "gotoSettings": "Settings" }, "messageInput": { - "title": "I-Type ang message", + "title": "I-type ang message", "multiline": "Multiline" }, "noFiles": { @@ -384,19 +384,19 @@ }, "quickSaveNotice": { "title": "@:general.quickSave", - "content": "Ang mga file request ay awtomatikong tinatanggap. Mabatid lamang na ang lahat ng nasa lokal na network ay maaaring mag-padala sa iyo ng mga file." + "content": "Ang mga file request ay awtomatikong tinatanggap. Mabatid lamang na ang lahat ng nasa lokal na network ay maaaring magpadala sa iyo ng mga file." }, "sendModeHelp": { "title": "Send modes", "single": "Magpadala ng mga file sa iisang recipient o tatanggap. Ang mga pagpipilian ay maaalis pagkatapos ipadala ang file.", "multiple": "Magpadala ng mga file sa maraming recipient o tatanggap. Ang mga pagpipilian ay hindi maaalis.", - "link": "Ang mga recipient o tatanggap na walang nakainstall na LocalSend ay maaring mag download nang mga napiling files sa pamamagitan ng pagbukas ng link sa kanilang browser." + "link": "Ang mga recipient o tatanggap na walang nakainstall na LocalSend ay maaring mag download nang mga napiling file sa pamamagitan ng pagbukas ng link sa kanilang browser." } }, "tray": { "@info": "Apple Guidelines are very strict about the 'close' wording.", "open": "@:general.open", - "close": "Quit LocalSend" + "close": "Isara ang LocalSend" }, "web": { "waiting": "@:sendPage.waiting", @@ -419,11 +419,11 @@ "unSupportedAssetType": "Hindi suportadong file type.", "unableToAccessAll": "Hindi ma-access ang lahat ng mga file sa device", "viewingLimitedAssetsTip": "Makikita lamang ang mga file at mga album na accessible sa app", - "changeAccessibleLimitedAssets": "I-Click para i-update ang accessible na mga file", + "changeAccessibleLimitedAssets": "I-click para i-update ang accessible na mga file", "accessAllTip": "Ang app na ito ay kaya lamang mag-access ng iilang mga file sa device. Magtungo sa system settings at i-allow ang app para ma-access ang lahat ng media sa device.", "goToSystemSettings": "Magpunta sa system settings", "accessLimitedAssets": "Ituloy nang limitadong access", - "accessiblePathName": "Accessible na mga files", + "accessiblePathName": "Accessible na mga file", "sTypeAudioLabel": "Audio", "sTypeImageLabel": "Image", "sTypeVideoLabel": "Video", From f5525bcd3edfe5234a103d247a9edb33add29188 Mon Sep 17 00:00:00 2001 From: Zayd Krunz <70227235+ShrootBuck@users.noreply.github.com> Date: Fri, 10 Nov 2023 13:22:14 -0700 Subject: [PATCH 10/31] Update index.html (#879) --- app/assets/web/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/web/index.html b/app/assets/web/index.html index b00988cca6c..ec6f8ed1b96 100644 --- a/app/assets/web/index.html +++ b/app/assets/web/index.html @@ -96,7 +96,7 @@

LocalSend

From e71c2947271a02ff10c37f5ccbbefebb2620e2fd Mon Sep 17 00:00:00 2001 From: Rad Date: Sun, 12 Nov 2023 17:22:40 +0100 Subject: [PATCH 11/31] i18n: Update Polish translation (#890) --- app/assets/i18n/_missing_translations_pl.json | 26 +++++++++---------- app/assets/i18n/strings_pl.i18n.json | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/app/assets/i18n/_missing_translations_pl.json b/app/assets/i18n/_missing_translations_pl.json index 4fe9f4812f3..d701cea9f86 100644 --- a/app/assets/i18n/_missing_translations_pl.json +++ b/app/assets/i18n/_missing_translations_pl.json @@ -4,12 +4,12 @@ "After editing this file, you can run 'dart run slang apply --locale=pl' to quickly apply the newly added translations." ], "general": { - "delete": "Delete", - "noItemInClipboard": "No item in Clipboard" + "delete": "Usuń", + "noItemInClipboard": "Schowek jest pusty" }, "sendTab": { "picker": { - "clipboard": "Paste" + "clipboard": "Wklej" } }, "settingsTab": { @@ -21,25 +21,25 @@ }, "dialogs": { "favoriteDialog": { - "title": "Favorites", - "noFavorites": "No favorites devices yet.", - "addFavorite": "Add" + "title": "Ulubione", + "noFavorites": "Brak ulubionych urządzeń.", + "addFavorite": "Dodaj" }, "favoriteDeleteDialog": { - "title": "Delete from favorites", - "content": "Do you really want to delete from favorites \"{name}\"?" + "title": "Usuń z ulubionych", + "content": "Czy na pewno chcesz usunąć z ulubionych \"{name}\"?" }, "favoriteEditDialog": { - "titleAdd": "Add to favorites", - "titleEdit": "Adjustment", + "titleAdd": "Dodaj do ulubionych", + "titleEdit": "Dostosuj", "name": "Alias", "auto": "(auto)", - "ip": "IP Address", + "ip": "Adres IP", "port": "Port" }, "historyClearDialog": { - "title": "Clear history", - "content": "Do you really want to delete the entire history?" + "title": "Wyczyść historię", + "content": "Czy na pewno chcesz usunąć całą historię?" } } } diff --git a/app/assets/i18n/strings_pl.i18n.json b/app/assets/i18n/strings_pl.i18n.json index acfeaf9e638..3edec824611 100644 --- a/app/assets/i18n/strings_pl.i18n.json +++ b/app/assets/i18n/strings_pl.i18n.json @@ -78,7 +78,7 @@ "title": "Ustawienia", "general": { "title": "Ogólne", - "brightness": "Jasność", + "brightness": "Motyw", "brightnessOptions": { "system": "System", "dark": "Ciemny", From 08ed55369b76c9065a14a636321416f4a1b8d7d4 Mon Sep 17 00:00:00 2001 From: Petros Kyladitis Date: Tue, 14 Nov 2023 18:18:14 +0200 Subject: [PATCH 12/31] added greek (el) language (#892) --- app/assets/i18n/strings_el.i18n.json | 439 +++++++++++++++++++++++++++ 1 file changed, 439 insertions(+) create mode 100644 app/assets/i18n/strings_el.i18n.json diff --git a/app/assets/i18n/strings_el.i18n.json b/app/assets/i18n/strings_el.i18n.json new file mode 100644 index 00000000000..fb54e35976c --- /dev/null +++ b/app/assets/i18n/strings_el.i18n.json @@ -0,0 +1,439 @@ +{ + "locale": "Ελληνικά", + "appName": "LocalSend", + "general": { + "accept": "Αποδοχή", + "accepted": "Αποδεκτό", + "add": "Προσθήκη", + "advanced": "Προχωρημένες", + "cancel": "Άκυρο", + "close": "Κλείσιμο", + "confirm": "Επιβεβαίωση", + "continueStr": "Συνέχεια", + "copy": "Αντιγραφή", + "copiedToClipboard": "Αντιγράφηκε στο Πρόχειρο", + "decline": "Απόρριψη", + "done": "Έγινε", + "delete": "Διαγραφή", + "edit": "Επεξεργασία", + "error": "Σφάλμα", + "example": "Παράδειγμα", + "files": "Αρχεία", + "finished": "Ολοκληρώθηκε", + "hide": "Απόκρυψη", + "off": "Απενεργοποίηση", + "offline": "Εκτός σύνδεσης", + "on": "Ενεργοποίηση", + "online": "Σε σύνδεση", + "open": "Άνοιγμα", + "queue": "Ουρά", + "quickSave": "Γρήγορη Αποθήκευση", + "renamed": "Μετονομάστηκε", + "reset": "Επαναφορά", + "restart": "Επανεκκίνηση", + "settings": "Ρυθμίσεις", + "skipped": "Παράλειψη", + "start": "Έναρξη", + "stop": "Διακοπή", + "save": "Αποθήκευση", + "unchanged": "Χωρίς αλλαγές", + "unknown": "Αγνωστο", + "noItemInClipboard": "Κανένα στοιχείο στο Πρόχειρο" + }, + "receiveTab": { + "title": "Λήψη", + "infoBox": { + "ip": "IP:", + "port": "Θύρα:", + "alias": "Όνομα συσκευής:" + } + }, + "sendTab": { + "title": "Αποστολή", + "selection": { + "title": "Επιλογή", + "files": "Αρχεία: {files}", + "size": "Μέγεθος: {size}" + }, + "picker": { + "file": "Αρχείο", + "folder": "Φάκελος", + "media": "Μέσα", + "text": "Κείμενο", + "app": "Εφαρμογή", + "clipboard": "Επικόλληση" + }, + "shareIntentInfo": "Μπορείτε επίσης να χρησιμοποιήσετε τη δυνατότητα \"Κοινή χρήση\" της κινητής συσκευής σας για να επιλέξετε αρχεία πιο εύκολα.", + "nearbyDevices": "Κοντινές συσκευές", + "thisDevice": "Αυτή η συσκευή", + "scan": "Αναζήτηση για συσκευές", + "sendMode": "Λειτουργία αποστολής", + "sendModes": { + "single": "Ένας παραλήπτης", + "multiple": "Πολλαπλοί παραλήπτες", + "link": "Διαμοιρασμός μέσω συνδέσμου" + }, + "sendModeHelp": "Επεξήγηση", + "help": "Βεβαιωθείτε ότι ο επιθυμητός παραλήπτης βρίσκεται επίσης στο ίδιο δίκτυο Wi-Fi.", + "placeItems": "Τοποθετήστε στοιχεία για διαμοιρασμό." + }, + "settingsTab": { + "title": "Ρυθμίσεις", + "general": { + "title": "Γενικά", + "brightness": "Θέμα", + "brightnessOptions": { + "system": "Σύστημα", + "dark": "Σκοτεινό", + "light": "Φωτεινό" + }, + "color": "Χρώμα", + "colorOptions": { + "system": "Σύστημα", + "oled": "OLED" + }, + "language": "Γλώσσα", + "languageOptions": { + "system": "Σύστημα" + }, + "saveWindowPlacement": "Έξοδος: Αποθήκευση θέσης παραθύρου", + "minimizeToTray": "Έξοδος: Ελαχιστοποίηση στη γραμμή εργασιών/μενού", + "launchAtStartup": "Αυτόματη εκκίνηση μετά τη σύνδεση", + "launchMinimized": "Αυτόματη εκκίνηση: Έναρξη ελαχιστοποιημένο", + "animations": "Οπτικά εφέ" + }, + "receive": { + "title": "Λήψη", + "quickSave": "@:general.quickSave", + "destination": "Προορισμός", + "downloads": "(Λήψεις)", + "saveToGallery": "Αποθήκευση μέσου στη συλλογή", + "saveToHistory": "Αποθήκευση στο ιστορικό" + }, + "network": { + "title": "Δίκτυο", + "needRestart": "Κάντε επανεκκίνηση του διακομιστή για να εφαρμοστούν οι ρυθμίσεις!", + "server": "Διακομιστής", + "alias": "Όνομα συσκευής", + "deviceType": "Τύπος συσκευής", + "deviceModel": "Μοντέλο συσκευής", + "port": "Θύρα", + "portWarning": "Ενδέχεται να μην εντοπιστείτε από άλλες συσκευές επειδή χρησιμοποιείτε μια προσαρμοσμένη θύρα. (προεπιλογή: {defaultPort})", + "encryption": "Κρυπτογράφηση", + "multicastGroup": "Αναμετάδοση", + "multicastGroupWarning": "Ενδέχεται να μην εντοπιστείτε από άλλες συσκευές επειδή χρησιμοποιείτε μια προσαρμοσμένη διεύθυνση αναμετάδοσης. (προεπιλογή: {defaultMulticast})" + }, + "advancedSettings": "Προχωρημένες ρυθμίσεις" + }, + "troubleshootPage": { + "title": "Αντιμετώπιση προβλημάτων", + "subTitle": "Αυτή η εφαρμογή δεν λειτουργεί όπως αναμένεται; Εδώ μπορείτε να βρείτε κοινές λύσεις.", + "solution": "Λύση:", + "fixButton": "Αυτόματη διόρθωση", + "firewall": { + "symptom": "Αυτή η εφαρμογή μπορεί να στείλει αρχεία σε άλλες συσκευές, αλλά άλλες συσκευές δεν μπορούν να στείλουν αρχεία σε αυτήν τη συσκευή.", + "solution": "Αυτό είναι πιθανότατα ένα ζήτημα του τείχους προστασίας. Μπορείτε να το λύσετε επιτρέποντας τις εισερχόμενες συνδέσεις (UDP και TCP) στη θύρα {port}.", + "openFirewall": "Άνοιγμα Τείχους Προστασίας" + }, + "noConnection": { + "symptom": "Και οι δύο συσκευές δεν μπορούν να ανακαλύψουν η μία την άλλη ούτε μπορούν να μοιραστούν αρχεία.", + "solution": "Υπάρχει το πρόβλημα και από τις δύο πλευρές; Πρέπει να βεβαιωθείτε ότι και οι δύο συσκευές βρίσκονται στο ίδιο δίκτυο Wi-Fi και μοιράζονται την ίδια διαμόρφωση (θύρα, διεύθυνση αναμετάδοσης, κρυπτογράφηση). Το wifi ενδέχεται να μην επιτρέπει την επικοινωνία μεταξύ των συμμετεχόντων. Σε αυτήν την περίπτωση, αυτή η επιλογή πρέπει να είναι ενεργοποιημένη στο δρομολογητή." + } + }, + "receiveHistoryPage": { + "title": "Ιστορικό", + "openFolder": "Άνοιγμα φακέλου", + "deleteHistory": "Διαγραφή ιστορικού", + "empty": "Το ιστορικό είναι κενό.", + "entryActions": { + "open": "Άνοιγμα αρχείου", + "info": "Πληροφορίες", + "deleteFromHistory": "Διαγραφή από το ιστορικό" + } + }, + "apkPickerPage": { + "title": "Εφαρμογές (APK)", + "excludeSystemApps": "Εξαίρεση εφαρμογών συστήματος", + "excludeAppsWithoutLaunchIntent": "Εξαίρεση μη εκκινήσιμων εφαρμογών", + "apps": "{n} Εφαρμογές" + }, + "selectedFilesPage": { + "deleteAll": "Διαγραφή όλων" + }, + "receivePage": { + "subTitle": { + "one": "θέλει να σου στείλει ένα αρχείο.", + "other": "θέλει να σου στείλει {n} αρχεία." + }, + "subTitleMessage": "σου έστειλε ένα μήνυμα:", + "subTitleLink": "σου έστειλε ένα σύνδεσμο:", + "canceled": "Ο αποστολέας ακύρωσε το αίτημα." + }, + "receiveOptionsPage": { + "title": "Επιλογές", + "destination": "@:settingsTab.receive.destination", + "appDirectory": "(Φάκελος LocalSend)", + "saveToGallery": "@:settingsTab.receive.saveToGallery", + "saveToGalleryOff": "Απενεργοποιήθηκε αυτόματα επειδή υπάρχουν κατάλογοι." + }, + "sendPage": { + "waiting": "Αναμονή για απάντηση...", + "rejected": "Ο παραλήπτης απέρριψε το αίτημα.", + "busy": "Ο παραλήπτης είναι απασχολημένος με άλλο αίτημα." + }, + "progressPage": { + "titleSending": "Γίνεται αποστολή αρχείων", + "titleReceiving": "Γίνεται λήψη αρχείων", + "savedToGallery": "Αποθηκεύτηκε στις Φωτογραφίες", + "total": { + "title": { + "sending": "Συνολική πρόοδος ({time})", + "finishedError": "Ολοκληρώθηκε με σφάλμα", + "canceledSender": "Ακυρώθηκε από τον αποστολέα", + "canceledReceiver": "Ακυρώθηκε από τον παραλήπτη" + }, + "count": "Αρχεία: {curr} / {n}", + "size": "Μέγεθος: {curr} / {n}", + "speed": "Ταχύτητα: {speed}/s" + } + }, + "webSharePage": { + "title": "Διαμοιρασμός μέσω συνδέσμου", + "loading": "Εκκίνηση διακομιστή...", + "stopping": "Σταμάτημα διακομιστή...", + "error": "Ένα σφάλμα προέκυψε κατά την εκκίνηση του διακομιστή.", + "openLink": { + "one": "Άνοιγμα αυτού του συνδέσμου στον φυλλομετρητή:", + "other": "Άνοιγμα ενός από αυτούς τους συνδέσμους στον φυλλομετρητή:" + }, + "requests": "Αιτήματα", + "noRequests": "Κανένα αίτμηα ακόμα.", + "encryption": "@:settingsTab.network.encryption", + "encryptionHint": "Το LocalSend χρησιμοποιεί αυτο-υπογεγραμμένο πιστοποιητικό. Χρειάζεται να το αποθεχτείτε στον φυλλομετρητή.", + "pendingRequests": "Αναμονή αιτημάτων: {n}" + }, + "aboutPage": { + "title": "Σχετικά με το LocalSend" + }, + "changelogPage": { + "title": "Καταγραφή αλλαγών" + }, + "aliasGenerator(ignoreMissing, ignoreGpt)": { + "@info": "Different locales may have different words, it may not match 1:1", + "adjectives": [ + "Λατρευτό", + "Πανεμορφο", + "Μεγάλο", + "Λαμπερό", + "Ζουμερό", + "Καλοπροαίρετο", + "Δροσερό", + "Χαριτωμένο", + "Πονηρό", + "Καταχθώνιο", + "Ενεργητικό", + "Αποτελεσματικό", + "Φανταστικό", + "Γρήγορο", + "Ντροπαλό", + "Φρέσκο", + "Καλό", + "Υπέροχο", + "Εξαιρετικό", + "Τεμπέλικο", + "Θερμό", + "Ψυχρό", + "Νευρικό", + "Ήρεμο", + "Καθαρό", + "Ομορφο", + "Υπομονετικο", + "Αρκετά", + "Χαρούμενο", + "Πλούσιο", + "Μυστικό", + "Έξυπνο", + "Ανυπόμονο", + "Οκνηρό", + "Νυσταγμένο", + "Ισχυρό", + "Τακτοποιημένο", + "Σοφό" + ], + "fruits": [ + "Μήλο", + "Αβοκάντο", + "Μανταρίνι", + "Βατόμουρο", + "Σκόρδο", + "Μπρόκολο", + "Καρότο", + "Κεράσι", + "Μαρούλι", + "Σταφύλι", + "Λεμόνι", + "Λάχανο", + "Μάνγκο", + "Πεπόνι", + "Μανιτάρι", + "Κρεμμύδι", + "Πορτοκάλι", + "Κολοκύθι", + "Ροδάκινο", + "Αχλάδι", + "Καρπούζι", + "Κάστανο", + "Πράσο", + "Ακτινίδιο", + "Σύκο", + "Αγγούρι" + ], + "combination": "{adjective} {fruit}", + "@combination": "In some languages, the adjective must be last." + }, + "dialogs": { + "addFile": { + "title": "Προσθήκη στις επιλογές", + "content": "Τι θέλετε να προστεθεί;" + }, + "addressInput": { + "title": "Εισαγωγή διεύθυνσης", + "hashtag": "Hashtag", + "ip": "Διεύθυνση IP", + "recentlyUsed": "Χρησιμοποιήθηκε πρόσφατα: " + }, + "cancelSession": { + "title": "Ακύρωση της μεταφοράς του αρχείου", + "content": "Θέλετε σίγουρα να ακυρωθεί η μεταφορά του αρχείου?" + }, + "cannotOpenFile": { + "title": "Δεν μπορεί να ανοιχτεί το αρχείο", + "content": "Δεν μπορεί να ανοιχτεί το \"{file}\". Έχετε μήπως μετακινήσει, μενονομάσει ή διαγράψει το αρχείο;" + }, + "encryptionDisabledNotice": { + "title": "Η κρυπτογράφηση απενεργοποιήθηκε", + "content": "Η επικοινωνία πραγματοποιείται πλέον μέσω του μη κρυπτογραφημένου πρωτοκόλλου HTTP. Για να χρησιμοποιήσετε το HTTPS, ενεργοποιήστε ξανά την κρυπτογράφηση." + }, + "errorDialog": { + "title": "@:general.error" + }, + "favoriteDialog": { + "title": "Αγαπημένα", + "noFavorites": "Καμία αγαπημένη συσκευή προς το παρόν.", + "addFavorite": "Προσθήκη" + }, + "favoriteDeleteDialog": { + "title": "Διαγραφή από τα αγαπημένα", + "content": "Θέλετε σίγουρα να διαγραφεί από τα αγαπημένα το \"{name}\"?" + }, + "favoriteEditDialog": { + "titleAdd": "Προσθήκη στα αγαπημένα", + "titleEdit": "Ρυθμίσεις", + "name": "Όνομα συσκευής", + "auto": "(αυτόματα)", + "ip": "Διεύθυνση IP", + "port": "Θύρα" + }, + "fileInfo": { + "title": "Πληροφορίες αρχείου", + "fileName": "Όνομα αρχείου:", + "path": "Μονοπάτι:", + "size": "Μέγεθος:", + "sender": "Αποστολέας:", + "time": "Ώρα:" + }, + "fileNameInput": { + "title": "Εισάγετε το όνομα του αρχείου", + "original": "Πρωτότυπο: {original}" + }, + "historyClearDialog": { + "title": "Καθαρισμός ιστορικού", + "content": "Θέλετε σίγουρα να διαγράψετε όλο το ιστορικό;" + }, + "localNetworkUnauthorized": { + "title": "@:dialogs.noPermission.title", + "description": "LocalSend can't find other devices without having the permission to scan the local network. Please grant this permission in the settings.", + "gotoSettings": "Ρυθμίσεις" + }, + "messageInput": { + "title": "Τύπος μηνύματος", + "multiline": "Πολλαπλών γραμμών" + }, + "noFiles": { + "title": "Κανένα αρχείο δεν επιλέχθηκε", + "content": "Παρακαλώ επιλέξτε τουλάχιστον ένα αρχείο." + }, + "noPermission": { + "title": "Χωρίς άδεια", + "content": "Δεν έχετε παραχωρήσει τις απαραίτητες άδειες. Παρακαλώ παραχωρήστε τα στις ρυθμίσεις." + }, + "notAvailableOnPlatform": { + "title": "Μη διαθέσιμο", + "content": "Αυτό το χαρακτηριστικό είναι διαθέσιμο μόνο σε:" + }, + "qr": { + "title": "Κώδικας QR" + }, + "quickActions": { + "title": "Γρήγορες Ενέργειες", + "counter": "Μετρητής", + "prefix": "Πρόθεμα", + "padZero": "Συμπλήρωση με μηδενικά", + "sortBeforeCount": "Ταξινόμηση αλφαβητικά εκ των προτέρων", + "random": "Τυχαία" + }, + "quickSaveNotice": { + "title": "@:general.quickSave", + "content": "Τα αιτήματα αρχείων γίνονται αυτόματα δεκτά. Έχετε υπόψη σας ότι όλοι στο τοπικό δίκτυο μπορούν να σας στείλουν αρχεία." + }, + "sendModeHelp": { + "title": "Λειτουργίες αποστολής", + "single": "Στέλνει αρχεία σε έναν παραλήπτη. Η επιλογή θα διαγραφεί μετά την ολοκλήρωση της μεταφοράς του αρχείου.", + "multiple": "Στέλνει αρχεία σε πολλούς παραλήπτες. Η επιλογή δεν θα διαγραφεί.", + "link": "Οι παραλήπτες που δεν έχουν εγκαταστήσει το LocalSend μπορούν να πραγματοποιήσουν λήψη των επιλεγμένων αρχείων ανοίγοντας τον σύνδεσμο στον φυλλομετρητή τους." + } + }, + "tray": { + "@info": "Apple Guidelines are very strict about the 'close' wording.", + "open": "@:general.open", + "close": "Έξοδος από το LocalSend" + }, + "web": { + "waiting": "@:sendPage.waiting", + "rejected": "Απορρίφθηκε", + "files": "Αρχεία", + "fileName": "Όνομα αρχείου", + "size": "Μέγεθος" + }, + "assetPicker": { + "@info": "Translations for the Media selection tool for Android and Iphone", + "confirm": "Επιβεβαιώση", + "cancel": "Ακύρωση", + "edit": "Επεξεργασία", + "gifIndicator": "GIF", + "loadFailed": "Η φόρτωση απέτυχε", + "original": "Προέλευση", + "preview": "Προεπισκόπηση", + "select": "Επιλογή", + "emptyList": "Κενή λίστα", + "unSupportedAssetType": "Μη υποστηριζόμενος τύπος αρχείου.", + "unableToAccessAll": "Δεν είναι δυνατή η πρόσβαση σε όλα τα αρχεία της συσκευής", + "viewingLimitedAssetsTip": "Προβολή μόνο των αρχείων και άλμπουμ που είναι προσβάσιμα από την εφαρμογή.", + "changeAccessibleLimitedAssets": "Κάντε κλικ για ενημέρωση των προσβάσιμων αρχείων", + "accessAllTip": "Η εφαρμογή μπορεί να έχει πρόσβαση μόνο σε ορισμένα αρχεία στη συσκευή. Μεταβείτε στις ρυθμίσεις συστήματος και επιτρέψτε στην εφαρμογή να έχει πρόσβαση σε όλα τα μέσα της συσκευής.", + "goToSystemSettings": "Μεταβείτε στις ρυθμίσεις συστήματος", + "accessLimitedAssets": "Συνεχίστε με περιορισμένη πρόσβαση", + "accessiblePathName": "Προσβάσιμα αρχεία", + "sTypeAudioLabel": "Ήχος", + "sTypeImageLabel": "Εικόνα", + "sTypeVideoLabel": "Βίντεο", + "sTypeOtherLabel": "Άλλα μέσα", + "sActionPlayHint": "αναπαραγωγή", + "sActionPreviewHint": "προεπισκόπηση", + "sActionSelectHint": "επιλογή", + "sActionSwitchPathLabel": "αλλαγή μονοπατιού", + "sActionUseCameraHint": "χρήση κάμερας", + "sNameDurationLabel": "διάρκεια", + "sUnitAssetCountLabel": "μετρητής" + } +} From 1cdb25f491fa346887c6dd34d2684a24885207b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Qichen=20Liu=20=E5=88=98=E5=90=AF=E8=BE=B0?= <74327704+Q1CHENL@users.noreply.github.com> Date: Wed, 15 Nov 2023 01:44:44 +0100 Subject: [PATCH 13/31] Added feature for macOS: command+w to close the window without quiting the app (#897) --- app/lib/widget/watcher/shortcut_watcher.dart | 19 +++++++++++++++++-- app/lib/widget/watcher/window_watcher.dart | 5 +++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/app/lib/widget/watcher/shortcut_watcher.dart b/app/lib/widget/watcher/shortcut_watcher.dart index 22678a25b9d..de7da31ce8c 100644 --- a/app/lib/widget/watcher/shortcut_watcher.dart +++ b/app/lib/widget/watcher/shortcut_watcher.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:localsend_app/util/native/file_picker.dart'; import 'package:localsend_app/util/native/platform_check.dart'; +import 'package:localsend_app/widget/watcher/window_watcher.dart'; import 'package:refena_flutter/refena_flutter.dart'; import 'package:routerino/routerino.dart'; @@ -22,21 +23,33 @@ class ShortcutWatcher extends StatelessWidget { // Add Control+Q binding for Linux // https://github.com/localsend/localsend/issues/194 if (checkPlatform([TargetPlatform.linux])) LogicalKeySet(LogicalKeyboardKey.control, LogicalKeyboardKey.keyQ): _ExitAppIntent(), + // Add Command+W to close the window for macOS + if (checkPlatform([TargetPlatform.macOS])) LogicalKeySet(LogicalKeyboardKey.meta, LogicalKeyboardKey.keyW): _CloseWindowIntent(), LogicalKeySet(LogicalKeyboardKey.escape): _PopPageIntent(), // Control+V and Command+V LogicalKeySet(LogicalKeyboardKey.control, LogicalKeyboardKey.keyV): _PasteIntent(), LogicalKeySet(LogicalKeyboardKey.meta, LogicalKeyboardKey.keyV): _PasteIntent(), + }, child: Actions( actions: { _ExitAppIntent: CallbackAction(onInvoke: (_) => exit(0)), - _PopPageIntent: CallbackAction(onInvoke: (_) async => Navigator.of(Routerino.context).maybePop()), + _PopPageIntent: CallbackAction( + onInvoke: (_) async => + Navigator.of(Routerino.context).maybePop()), _PasteIntent: CallbackAction(onInvoke: (_) async { - await context.ref.dispatchAsync(PickFileAction(option: FilePickerOption.clipboard, context: context)); + await context.ref.dispatchAsync(PickFileAction( + option: FilePickerOption.clipboard, context: context)); return null; }), + _CloseWindowIntent: CallbackAction<_CloseWindowIntent>( + onInvoke: (_) async { + await WindowWatcher.closeWindow(context); + return null; + }, + ), }, child: child, ), @@ -49,3 +62,5 @@ class _ExitAppIntent extends Intent {} class _PopPageIntent extends Intent {} class _PasteIntent extends Intent {} + +class _CloseWindowIntent extends Intent {} diff --git a/app/lib/widget/watcher/window_watcher.dart b/app/lib/widget/watcher/window_watcher.dart index ad500fffc0b..37469c42717 100644 --- a/app/lib/widget/watcher/window_watcher.dart +++ b/app/lib/widget/watcher/window_watcher.dart @@ -22,6 +22,11 @@ class WindowWatcher extends StatefulWidget { @override State createState() => _WindowWatcherState(); + + static Future closeWindow(BuildContext context) async { + final state = context.findAncestorStateOfType<_WindowWatcherState>(); + await state?.onWindowClose(); + } } class _WindowWatcherState extends State with WindowListener, Refena { From 3e521436a06b5656f18551c36775085dc3694afd Mon Sep 17 00:00:00 2001 From: Farshad Gh <53800521+farshad991@users.noreply.github.com> Date: Wed, 15 Nov 2023 04:17:25 +0330 Subject: [PATCH 14/31] Update _missing_translations_fa.json (#894) --- app/assets/i18n/_missing_translations_fa.json | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/app/assets/i18n/_missing_translations_fa.json b/app/assets/i18n/_missing_translations_fa.json index 0b35eec076c..c527d4eba8f 100644 --- a/app/assets/i18n/_missing_translations_fa.json +++ b/app/assets/i18n/_missing_translations_fa.json @@ -4,29 +4,29 @@ "After editing this file, you can run 'dart run slang apply --locale=fa' to quickly apply the newly added translations." ], "general": { - "delete": "Delete" + "delete": "حذف" }, "dialogs": { "favoriteDialog": { - "title": "Favorites", - "noFavorites": "No favorites devices yet.", - "addFavorite": "Add" + "title": "علاقه‌مندی‌ها", + "noFavorites": "هنوز دستگاهی اضافه نشده", + "addFavorite": "افزودن" }, "favoriteDeleteDialog": { - "title": "Delete from favorites", - "content": "Do you really want to delete from favorites \"{name}\"?" + "title": "حذف از علاقه‌مندی‌ها", + "content": "واقعاً می خواهید از علاقه‌مندی‌ها حذف کنید \"{name}\"?" }, "favoriteEditDialog": { - "titleAdd": "Add to favorites", - "titleEdit": "Adjustment", - "name": "Alias", - "auto": "(auto)", - "ip": "IP Address", - "port": "Port" + "titleAdd": "افزودن به علاقه‌مندی‌ها", + "titleEdit": "تنظیمات", + "name": "نام مستعار", + "auto": "(خودکار)", + "ip": "آدرس آی پی", + "port": "پورت" }, "historyClearDialog": { - "title": "Clear history", - "content": "Do you really want to delete the entire history?" + "title": "پاکسازی تاریخچه", + "content": "واقعاً می خواهید کل تاریخچه را حذف کنید؟" } } } From e59a060cc7845ab78dcf9e4b8317476e0685c461 Mon Sep 17 00:00:00 2001 From: Muhammad Widodo Date: Sat, 18 Nov 2023 00:10:16 +0800 Subject: [PATCH 15/31] add duplicate files validation when pick image or files or directory (#904) --- .../selected_sending_files_provider.dart | 16 +++++++++++++--- app/lib/util/native/cross_file_converters.dart | 6 ++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/app/lib/provider/selection/selected_sending_files_provider.dart b/app/lib/provider/selection/selected_sending_files_provider.dart index 922347170c5..439af47a908 100644 --- a/app/lib/provider/selection/selected_sending_files_provider.dart +++ b/app/lib/provider/selection/selected_sending_files_provider.dart @@ -6,6 +6,7 @@ import 'package:localsend_app/model/cross_file.dart'; import 'package:localsend_app/model/file_type.dart'; import 'package:localsend_app/util/file_path_helper.dart'; import 'package:localsend_app/util/native/cache_helper.dart'; +import 'package:localsend_app/util/native/cross_file_converters.dart'; import 'package:logging/logging.dart'; import 'package:path/path.dart' as p; import 'package:refena_flutter/refena_flutter.dart'; @@ -119,8 +120,13 @@ class AddFilesAction extends AsyncReduxAction[]; for (final file in files) { // we do it sequential because there are bugs - // https://github.com/fluttercandies/flutter_photo_manager/issues/589 - newFiles.add(await converter(file)); + // https://github.com/fluttercandies/flutter_photo_manager/issues/589 + + final crossFile = await converter(file); + final isAlreadySelect = state.any((element) => element.isSameFile(otherFile: crossFile)); + if (!isAlreadySelect) { + newFiles.add(crossFile); + } } return List.unmodifiable([ ...state, @@ -153,7 +159,11 @@ class AddDirectoryAction extends AsyncReduxAction element.isSameFile(otherFile: file)); + if (!isAlreadySelect) { + newFiles.add(file); + } } } diff --git a/app/lib/util/native/cross_file_converters.dart b/app/lib/util/native/cross_file_converters.dart index 8fb44a0f38a..584322fe568 100644 --- a/app/lib/util/native/cross_file_converters.dart +++ b/app/lib/util/native/cross_file_converters.dart @@ -76,3 +76,9 @@ class CrossFileConverters { ); } } + +extension CompareFile on CrossFile { + bool isSameFile({required CrossFile otherFile}) { + return (path ?? '') == (otherFile.path ?? ''); + } +} From 166c45b8f52156a6712f71e49181c07679a42d39 Mon Sep 17 00:00:00 2001 From: Tien Do Nam Date: Fri, 17 Nov 2023 22:04:19 +0100 Subject: [PATCH 16/31] docs: add EXE installer --- CONTRIBUTING.md | 1 + README.md | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f3f506e7457..040b0dd0760 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -125,6 +125,7 @@ Binary distribution: |-------------|---------------|------------------------------| | Windows ZIP | [@Tienisto][] | | | MSIX | [@Tienisto][] | | +| EXE | [@Tienisto][] | | | APK | [@Tienisto][] | | | TAR | [@Tienisto][] | | | DEB | [@Tienisto][] | | diff --git a/README.md b/README.md index 29074327d30..8ee6a570f24 100644 --- a/README.md +++ b/README.md @@ -47,8 +47,8 @@ It is recommended to download the app either from an app store or from a package | [Scoop][] | [Homebrew][] | [AUR][] | [F-Droid][] | | | | [Chocolatey][] | [DMG Installer][latest] | [NixOS][] | [APK][latest] | | | | [MSIX Installer][latest] | | [TAR][latest] | | | | -| [Portable ZIP][latest] | | [DEB][latest] | | | | -| | | [AppImage][latest] | | | | +| [EXE Installer][latest] | | [DEB][latest] | | | | +| [Portable ZIP][latest] | | [AppImage][latest] | | | | Read more about [distribution channels][]. From 31275fe399f9fc0cb901e16a5bf0bc50f7a28b93 Mon Sep 17 00:00:00 2001 From: Tien Do Nam Date: Fri, 17 Nov 2023 22:11:12 +0100 Subject: [PATCH 17/31] i18n: add el to config --- CONTRIBUTING.md | 1 + app/assets/CHANGELOG.md | 5 + app/assets/i18n/_missing_translations_el.json | 6 + app/assets/i18n/_unused_translations.json | 1 + app/ios/Runner/Info.plist | 1 + app/lib/gen/strings.g.dart | 6 +- app/lib/gen/strings_el.g.dart | 907 ++++++++++++++++++ app/lib/gen/strings_fil_PH.g.dart | 48 +- app/lib/gen/strings_pl.g.dart | 2 +- app/macos/Runner/Info.plist | 1 + app/pubspec.yaml | 2 +- 11 files changed, 952 insertions(+), 28 deletions(-) create mode 100644 app/assets/i18n/_missing_translations_el.json create mode 100644 app/lib/gen/strings_el.g.dart diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 040b0dd0760..6b4ff3eacf7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -40,6 +40,7 @@ Thanks to all translators! | Czech | @Amereyeu | | German | Tien Do Nam (@Tienisto) | | Italian | @Francesco146 | +| Greek | Petros Kyladitis (@multipetros) | | Spanish | Esteban Daniel Saracho (@esaracho) | | Persian | @farshad991 | | French | @Nixuge | diff --git a/app/assets/CHANGELOG.md b/app/assets/CHANGELOG.md index e4be7aa2004..7b60cf66867 100644 --- a/app/assets/CHANGELOG.md +++ b/app/assets/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.13.0 (unreleased) + +- feat: ignore duplicate files when selected from file picker (@programmermager) +- i18n: add Greek (@multipetros) + ## 1.12.0 (2023-10-25) - feat: add favorites (@Tienisto) diff --git a/app/assets/i18n/_missing_translations_el.json b/app/assets/i18n/_missing_translations_el.json new file mode 100644 index 00000000000..dcd86656802 --- /dev/null +++ b/app/assets/i18n/_missing_translations_el.json @@ -0,0 +1,6 @@ +{ + "@@info": [ + "Here are translations that exist in but not in .", + "After editing this file, you can run 'dart run slang apply --locale=el' to quickly apply the newly added translations." + ] +} diff --git a/app/assets/i18n/_unused_translations.json b/app/assets/i18n/_unused_translations.json index de890798290..6587186e673 100644 --- a/app/assets/i18n/_unused_translations.json +++ b/app/assets/i18n/_unused_translations.json @@ -23,6 +23,7 @@ "ca": {}, "cs": {}, "de": {}, + "el": {}, "es-ES": {}, "eu": {}, "fa": {}, diff --git a/app/ios/Runner/Info.plist b/app/ios/Runner/Info.plist index a0844fc0072..9454d8350b9 100644 --- a/app/ios/Runner/Info.plist +++ b/app/ios/Runner/Info.plist @@ -59,6 +59,7 @@ cs de en + el es-ES eu fa diff --git a/app/lib/gen/strings.g.dart b/app/lib/gen/strings.g.dart index ec126a5a0bb..fef0c5f2457 100644 --- a/app/lib/gen/strings.g.dart +++ b/app/lib/gen/strings.g.dart @@ -3,8 +3,8 @@ /// Original: assets/i18n /// To regenerate, run: `dart run slang` /// -/// Locales: 32 -/// Strings: 8551 (267 per locale) +/// Locales: 33 +/// Strings: 8864 (268 per locale) // coverage:ignore-file @@ -21,6 +21,7 @@ part 'strings_bn.g.dart'; part 'strings_ca.g.dart'; part 'strings_cs.g.dart'; part 'strings_de.g.dart'; +part 'strings_el.g.dart'; part 'strings_es_ES.g.dart'; part 'strings_eu.g.dart'; part 'strings_fa.g.dart'; @@ -63,6 +64,7 @@ enum AppLocale with BaseAppLocale { ca(languageCode: 'ca', build: _StringsCa.build), cs(languageCode: 'cs', build: _StringsCs.build), de(languageCode: 'de', build: _StringsDe.build), + el(languageCode: 'el', build: _StringsEl.build), esEs(languageCode: 'es', countryCode: 'ES', build: _StringsEsEs.build), eu(languageCode: 'eu', build: _StringsEu.build), fa(languageCode: 'fa', build: _StringsFa.build), diff --git a/app/lib/gen/strings_el.g.dart b/app/lib/gen/strings_el.g.dart new file mode 100644 index 00000000000..bc8baac2251 --- /dev/null +++ b/app/lib/gen/strings_el.g.dart @@ -0,0 +1,907 @@ +part of 'strings.g.dart'; + +// Path: +class _StringsEl extends _StringsEn { + + /// You can call this constructor and build your own translation instance of this locale. + /// Constructing via the enum [AppLocale.build] is preferred. + _StringsEl.build({Map? overrides, PluralResolver? cardinalResolver, PluralResolver? ordinalResolver}) + : assert(overrides == null, 'Set "translation_overrides: true" in order to enable this feature.'), + $meta = TranslationMetadata( + locale: AppLocale.el, + overrides: overrides ?? {}, + cardinalResolver: cardinalResolver, + ordinalResolver: ordinalResolver, + ), + super.build(cardinalResolver: cardinalResolver, ordinalResolver: ordinalResolver); + + /// Metadata for the translations of . + @override final TranslationMetadata $meta; + + @override late final _StringsEl _root = this; // ignore: unused_field + + // Translations + @override String get locale => 'Ελληνικά'; + @override String get appName => 'LocalSend'; + @override late final _StringsGeneralEl general = _StringsGeneralEl._(_root); + @override late final _StringsReceiveTabEl receiveTab = _StringsReceiveTabEl._(_root); + @override late final _StringsSendTabEl sendTab = _StringsSendTabEl._(_root); + @override late final _StringsSettingsTabEl settingsTab = _StringsSettingsTabEl._(_root); + @override late final _StringsTroubleshootPageEl troubleshootPage = _StringsTroubleshootPageEl._(_root); + @override late final _StringsReceiveHistoryPageEl receiveHistoryPage = _StringsReceiveHistoryPageEl._(_root); + @override late final _StringsApkPickerPageEl apkPickerPage = _StringsApkPickerPageEl._(_root); + @override late final _StringsSelectedFilesPageEl selectedFilesPage = _StringsSelectedFilesPageEl._(_root); + @override late final _StringsReceivePageEl receivePage = _StringsReceivePageEl._(_root); + @override late final _StringsReceiveOptionsPageEl receiveOptionsPage = _StringsReceiveOptionsPageEl._(_root); + @override late final _StringsSendPageEl sendPage = _StringsSendPageEl._(_root); + @override late final _StringsProgressPageEl progressPage = _StringsProgressPageEl._(_root); + @override late final _StringsWebSharePageEl webSharePage = _StringsWebSharePageEl._(_root); + @override late final _StringsAboutPageEl aboutPage = _StringsAboutPageEl._(_root); + @override late final _StringsChangelogPageEl changelogPage = _StringsChangelogPageEl._(_root); + @override late final _StringsAliasGeneratorEl aliasGenerator = _StringsAliasGeneratorEl._(_root); + @override late final _StringsDialogsEl dialogs = _StringsDialogsEl._(_root); + @override late final _StringsTrayEl tray = _StringsTrayEl._(_root); + @override late final _StringsWebEl web = _StringsWebEl._(_root); + @override late final _StringsAssetPickerEl assetPicker = _StringsAssetPickerEl._(_root); +} + +// Path: general +class _StringsGeneralEl extends _StringsGeneralEn { + _StringsGeneralEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get accept => 'Αποδοχή'; + @override String get accepted => 'Αποδεκτό'; + @override String get add => 'Προσθήκη'; + @override String get advanced => 'Προχωρημένες'; + @override String get cancel => 'Άκυρο'; + @override String get close => 'Κλείσιμο'; + @override String get confirm => 'Επιβεβαίωση'; + @override String get continueStr => 'Συνέχεια'; + @override String get copy => 'Αντιγραφή'; + @override String get copiedToClipboard => 'Αντιγράφηκε στο Πρόχειρο'; + @override String get decline => 'Απόρριψη'; + @override String get done => 'Έγινε'; + @override String get delete => 'Διαγραφή'; + @override String get edit => 'Επεξεργασία'; + @override String get error => 'Σφάλμα'; + @override String get example => 'Παράδειγμα'; + @override String get files => 'Αρχεία'; + @override String get finished => 'Ολοκληρώθηκε'; + @override String get hide => 'Απόκρυψη'; + @override String get off => 'Απενεργοποίηση'; + @override String get offline => 'Εκτός σύνδεσης'; + @override String get on => 'Ενεργοποίηση'; + @override String get online => 'Σε σύνδεση'; + @override String get open => 'Άνοιγμα'; + @override String get queue => 'Ουρά'; + @override String get quickSave => 'Γρήγορη Αποθήκευση'; + @override String get renamed => 'Μετονομάστηκε'; + @override String get reset => 'Επαναφορά'; + @override String get restart => 'Επανεκκίνηση'; + @override String get settings => 'Ρυθμίσεις'; + @override String get skipped => 'Παράλειψη'; + @override String get start => 'Έναρξη'; + @override String get stop => 'Διακοπή'; + @override String get save => 'Αποθήκευση'; + @override String get unchanged => 'Χωρίς αλλαγές'; + @override String get unknown => 'Αγνωστο'; + @override String get noItemInClipboard => 'Κανένα στοιχείο στο Πρόχειρο'; +} + +// Path: receiveTab +class _StringsReceiveTabEl extends _StringsReceiveTabEn { + _StringsReceiveTabEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Λήψη'; + @override late final _StringsReceiveTabInfoBoxEl infoBox = _StringsReceiveTabInfoBoxEl._(_root); +} + +// Path: sendTab +class _StringsSendTabEl extends _StringsSendTabEn { + _StringsSendTabEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Αποστολή'; + @override late final _StringsSendTabSelectionEl selection = _StringsSendTabSelectionEl._(_root); + @override late final _StringsSendTabPickerEl picker = _StringsSendTabPickerEl._(_root); + @override String get shareIntentInfo => 'Μπορείτε επίσης να χρησιμοποιήσετε τη δυνατότητα "Κοινή χρήση" της κινητής συσκευής σας για να επιλέξετε αρχεία πιο εύκολα.'; + @override String get nearbyDevices => 'Κοντινές συσκευές'; + @override String get thisDevice => 'Αυτή η συσκευή'; + @override String get scan => 'Αναζήτηση για συσκευές'; + @override String get sendMode => 'Λειτουργία αποστολής'; + @override late final _StringsSendTabSendModesEl sendModes = _StringsSendTabSendModesEl._(_root); + @override String get sendModeHelp => 'Επεξήγηση'; + @override String get help => 'Βεβαιωθείτε ότι ο επιθυμητός παραλήπτης βρίσκεται επίσης στο ίδιο δίκτυο Wi-Fi.'; + @override String get placeItems => 'Τοποθετήστε στοιχεία για διαμοιρασμό.'; +} + +// Path: settingsTab +class _StringsSettingsTabEl extends _StringsSettingsTabEn { + _StringsSettingsTabEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Ρυθμίσεις'; + @override late final _StringsSettingsTabGeneralEl general = _StringsSettingsTabGeneralEl._(_root); + @override late final _StringsSettingsTabReceiveEl receive = _StringsSettingsTabReceiveEl._(_root); + @override late final _StringsSettingsTabNetworkEl network = _StringsSettingsTabNetworkEl._(_root); + @override String get advancedSettings => 'Προχωρημένες ρυθμίσεις'; +} + +// Path: troubleshootPage +class _StringsTroubleshootPageEl extends _StringsTroubleshootPageEn { + _StringsTroubleshootPageEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Αντιμετώπιση προβλημάτων'; + @override String get subTitle => 'Αυτή η εφαρμογή δεν λειτουργεί όπως αναμένεται; Εδώ μπορείτε να βρείτε κοινές λύσεις.'; + @override String get solution => 'Λύση:'; + @override String get fixButton => 'Αυτόματη διόρθωση'; + @override late final _StringsTroubleshootPageFirewallEl firewall = _StringsTroubleshootPageFirewallEl._(_root); + @override late final _StringsTroubleshootPageNoConnectionEl noConnection = _StringsTroubleshootPageNoConnectionEl._(_root); +} + +// Path: receiveHistoryPage +class _StringsReceiveHistoryPageEl extends _StringsReceiveHistoryPageEn { + _StringsReceiveHistoryPageEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Ιστορικό'; + @override String get openFolder => 'Άνοιγμα φακέλου'; + @override String get deleteHistory => 'Διαγραφή ιστορικού'; + @override String get empty => 'Το ιστορικό είναι κενό.'; + @override late final _StringsReceiveHistoryPageEntryActionsEl entryActions = _StringsReceiveHistoryPageEntryActionsEl._(_root); +} + +// Path: apkPickerPage +class _StringsApkPickerPageEl extends _StringsApkPickerPageEn { + _StringsApkPickerPageEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Εφαρμογές (APK)'; + @override String get excludeSystemApps => 'Εξαίρεση εφαρμογών συστήματος'; + @override String get excludeAppsWithoutLaunchIntent => 'Εξαίρεση μη εκκινήσιμων εφαρμογών'; + @override String apps({required Object n}) => '${n} Εφαρμογές'; +} + +// Path: selectedFilesPage +class _StringsSelectedFilesPageEl extends _StringsSelectedFilesPageEn { + _StringsSelectedFilesPageEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get deleteAll => 'Διαγραφή όλων'; +} + +// Path: receivePage +class _StringsReceivePageEl extends _StringsReceivePageEn { + _StringsReceivePageEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String subTitle({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('el'))(n, + one: 'θέλει να σου στείλει ένα αρχείο.', + other: 'θέλει να σου στείλει ${n} αρχεία.', + ); + @override String get subTitleMessage => 'σου έστειλε ένα μήνυμα:'; + @override String get subTitleLink => 'σου έστειλε ένα σύνδεσμο:'; + @override String get canceled => 'Ο αποστολέας ακύρωσε το αίτημα.'; +} + +// Path: receiveOptionsPage +class _StringsReceiveOptionsPageEl extends _StringsReceiveOptionsPageEn { + _StringsReceiveOptionsPageEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Επιλογές'; + @override String get destination => '${_root.settingsTab.receive.destination}'; + @override String get appDirectory => '(Φάκελος LocalSend)'; + @override String get saveToGallery => '${_root.settingsTab.receive.saveToGallery}'; + @override String get saveToGalleryOff => 'Απενεργοποιήθηκε αυτόματα επειδή υπάρχουν κατάλογοι.'; +} + +// Path: sendPage +class _StringsSendPageEl extends _StringsSendPageEn { + _StringsSendPageEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get waiting => 'Αναμονή για απάντηση...'; + @override String get rejected => 'Ο παραλήπτης απέρριψε το αίτημα.'; + @override String get busy => 'Ο παραλήπτης είναι απασχολημένος με άλλο αίτημα.'; +} + +// Path: progressPage +class _StringsProgressPageEl extends _StringsProgressPageEn { + _StringsProgressPageEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get titleSending => 'Γίνεται αποστολή αρχείων'; + @override String get titleReceiving => 'Γίνεται λήψη αρχείων'; + @override String get savedToGallery => 'Αποθηκεύτηκε στις Φωτογραφίες'; + @override late final _StringsProgressPageTotalEl total = _StringsProgressPageTotalEl._(_root); +} + +// Path: webSharePage +class _StringsWebSharePageEl extends _StringsWebSharePageEn { + _StringsWebSharePageEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Διαμοιρασμός μέσω συνδέσμου'; + @override String get loading => 'Εκκίνηση διακομιστή...'; + @override String get stopping => 'Σταμάτημα διακομιστή...'; + @override String get error => 'Ένα σφάλμα προέκυψε κατά την εκκίνηση του διακομιστή.'; + @override String openLink({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('el'))(n, + one: 'Άνοιγμα αυτού του συνδέσμου στον φυλλομετρητή:', + other: 'Άνοιγμα ενός από αυτούς τους συνδέσμους στον φυλλομετρητή:', + ); + @override String get requests => 'Αιτήματα'; + @override String get noRequests => 'Κανένα αίτμηα ακόμα.'; + @override String get encryption => '${_root.settingsTab.network.encryption}'; + @override String get encryptionHint => 'Το LocalSend χρησιμοποιεί αυτο-υπογεγραμμένο πιστοποιητικό. Χρειάζεται να το αποθεχτείτε στον φυλλομετρητή.'; + @override String pendingRequests({required Object n}) => 'Αναμονή αιτημάτων: ${n}'; +} + +// Path: aboutPage +class _StringsAboutPageEl extends _StringsAboutPageEn { + _StringsAboutPageEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Σχετικά με το LocalSend'; +} + +// Path: changelogPage +class _StringsChangelogPageEl extends _StringsChangelogPageEn { + _StringsChangelogPageEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Καταγραφή αλλαγών'; +} + +// Path: aliasGenerator +class _StringsAliasGeneratorEl extends _StringsAliasGeneratorEn { + _StringsAliasGeneratorEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override List get adjectives => [ + 'Λατρευτό', + 'Πανεμορφο', + 'Μεγάλο', + 'Λαμπερό', + 'Ζουμερό', + 'Καλοπροαίρετο', + 'Δροσερό', + 'Χαριτωμένο', + 'Πονηρό', + 'Καταχθώνιο', + 'Ενεργητικό', + 'Αποτελεσματικό', + 'Φανταστικό', + 'Γρήγορο', + 'Ντροπαλό', + 'Φρέσκο', + 'Καλό', + 'Υπέροχο', + 'Εξαιρετικό', + 'Τεμπέλικο', + 'Θερμό', + 'Ψυχρό', + 'Νευρικό', + 'Ήρεμο', + 'Καθαρό', + 'Ομορφο', + 'Υπομονετικο', + 'Αρκετά', + 'Χαρούμενο', + 'Πλούσιο', + 'Μυστικό', + 'Έξυπνο', + 'Ανυπόμονο', + 'Οκνηρό', + 'Νυσταγμένο', + 'Ισχυρό', + 'Τακτοποιημένο', + 'Σοφό', + ]; + @override List get fruits => [ + 'Μήλο', + 'Αβοκάντο', + 'Μανταρίνι', + 'Βατόμουρο', + 'Σκόρδο', + 'Μπρόκολο', + 'Καρότο', + 'Κεράσι', + 'Μαρούλι', + 'Σταφύλι', + 'Λεμόνι', + 'Λάχανο', + 'Μάνγκο', + 'Πεπόνι', + 'Μανιτάρι', + 'Κρεμμύδι', + 'Πορτοκάλι', + 'Κολοκύθι', + 'Ροδάκινο', + 'Αχλάδι', + 'Καρπούζι', + 'Κάστανο', + 'Πράσο', + 'Ακτινίδιο', + 'Σύκο', + 'Αγγούρι', + ]; + + /// In some languages, the adjective must be last. + @override String combination({required Object adjective, required Object fruit}) => '${adjective} ${fruit}'; +} + +// Path: dialogs +class _StringsDialogsEl extends _StringsDialogsEn { + _StringsDialogsEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override late final _StringsDialogsAddFileEl addFile = _StringsDialogsAddFileEl._(_root); + @override late final _StringsDialogsAddressInputEl addressInput = _StringsDialogsAddressInputEl._(_root); + @override late final _StringsDialogsCancelSessionEl cancelSession = _StringsDialogsCancelSessionEl._(_root); + @override late final _StringsDialogsCannotOpenFileEl cannotOpenFile = _StringsDialogsCannotOpenFileEl._(_root); + @override late final _StringsDialogsEncryptionDisabledNoticeEl encryptionDisabledNotice = _StringsDialogsEncryptionDisabledNoticeEl._(_root); + @override late final _StringsDialogsErrorDialogEl errorDialog = _StringsDialogsErrorDialogEl._(_root); + @override late final _StringsDialogsFavoriteDialogEl favoriteDialog = _StringsDialogsFavoriteDialogEl._(_root); + @override late final _StringsDialogsFavoriteDeleteDialogEl favoriteDeleteDialog = _StringsDialogsFavoriteDeleteDialogEl._(_root); + @override late final _StringsDialogsFavoriteEditDialogEl favoriteEditDialog = _StringsDialogsFavoriteEditDialogEl._(_root); + @override late final _StringsDialogsFileInfoEl fileInfo = _StringsDialogsFileInfoEl._(_root); + @override late final _StringsDialogsFileNameInputEl fileNameInput = _StringsDialogsFileNameInputEl._(_root); + @override late final _StringsDialogsHistoryClearDialogEl historyClearDialog = _StringsDialogsHistoryClearDialogEl._(_root); + @override late final _StringsDialogsLocalNetworkUnauthorizedEl localNetworkUnauthorized = _StringsDialogsLocalNetworkUnauthorizedEl._(_root); + @override late final _StringsDialogsMessageInputEl messageInput = _StringsDialogsMessageInputEl._(_root); + @override late final _StringsDialogsNoFilesEl noFiles = _StringsDialogsNoFilesEl._(_root); + @override late final _StringsDialogsNoPermissionEl noPermission = _StringsDialogsNoPermissionEl._(_root); + @override late final _StringsDialogsNotAvailableOnPlatformEl notAvailableOnPlatform = _StringsDialogsNotAvailableOnPlatformEl._(_root); + @override late final _StringsDialogsQrEl qr = _StringsDialogsQrEl._(_root); + @override late final _StringsDialogsQuickActionsEl quickActions = _StringsDialogsQuickActionsEl._(_root); + @override late final _StringsDialogsQuickSaveNoticeEl quickSaveNotice = _StringsDialogsQuickSaveNoticeEl._(_root); + @override late final _StringsDialogsSendModeHelpEl sendModeHelp = _StringsDialogsSendModeHelpEl._(_root); +} + +// Path: tray +class _StringsTrayEl extends _StringsTrayEn { + _StringsTrayEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get open => '${_root.general.open}'; + @override String get close => 'Έξοδος από το LocalSend'; +} + +// Path: web +class _StringsWebEl extends _StringsWebEn { + _StringsWebEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get waiting => '${_root.sendPage.waiting}'; + @override String get rejected => 'Απορρίφθηκε'; + @override String get files => 'Αρχεία'; + @override String get fileName => 'Όνομα αρχείου'; + @override String get size => 'Μέγεθος'; +} + +// Path: assetPicker +class _StringsAssetPickerEl extends _StringsAssetPickerEn { + _StringsAssetPickerEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get confirm => 'Επιβεβαιώση'; + @override String get cancel => 'Ακύρωση'; + @override String get edit => 'Επεξεργασία'; + @override String get gifIndicator => 'GIF'; + @override String get loadFailed => 'Η φόρτωση απέτυχε'; + @override String get original => 'Προέλευση'; + @override String get preview => 'Προεπισκόπηση'; + @override String get select => 'Επιλογή'; + @override String get emptyList => 'Κενή λίστα'; + @override String get unSupportedAssetType => 'Μη υποστηριζόμενος τύπος αρχείου.'; + @override String get unableToAccessAll => 'Δεν είναι δυνατή η πρόσβαση σε όλα τα αρχεία της συσκευής'; + @override String get viewingLimitedAssetsTip => 'Προβολή μόνο των αρχείων και άλμπουμ που είναι προσβάσιμα από την εφαρμογή.'; + @override String get changeAccessibleLimitedAssets => 'Κάντε κλικ για ενημέρωση των προσβάσιμων αρχείων'; + @override String get accessAllTip => 'Η εφαρμογή μπορεί να έχει πρόσβαση μόνο σε ορισμένα αρχεία στη συσκευή. Μεταβείτε στις ρυθμίσεις συστήματος και επιτρέψτε στην εφαρμογή να έχει πρόσβαση σε όλα τα μέσα της συσκευής.'; + @override String get goToSystemSettings => 'Μεταβείτε στις ρυθμίσεις συστήματος'; + @override String get accessLimitedAssets => 'Συνεχίστε με περιορισμένη πρόσβαση'; + @override String get accessiblePathName => 'Προσβάσιμα αρχεία'; + @override String get sTypeAudioLabel => 'Ήχος'; + @override String get sTypeImageLabel => 'Εικόνα'; + @override String get sTypeVideoLabel => 'Βίντεο'; + @override String get sTypeOtherLabel => 'Άλλα μέσα'; + @override String get sActionPlayHint => 'αναπαραγωγή'; + @override String get sActionPreviewHint => 'προεπισκόπηση'; + @override String get sActionSelectHint => 'επιλογή'; + @override String get sActionSwitchPathLabel => 'αλλαγή μονοπατιού'; + @override String get sActionUseCameraHint => 'χρήση κάμερας'; + @override String get sNameDurationLabel => 'διάρκεια'; + @override String get sUnitAssetCountLabel => 'μετρητής'; +} + +// Path: receiveTab.infoBox +class _StringsReceiveTabInfoBoxEl extends _StringsReceiveTabInfoBoxEn { + _StringsReceiveTabInfoBoxEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get ip => 'IP:'; + @override String get port => 'Θύρα:'; + @override String get alias => 'Όνομα συσκευής:'; +} + +// Path: sendTab.selection +class _StringsSendTabSelectionEl extends _StringsSendTabSelectionEn { + _StringsSendTabSelectionEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Επιλογή'; + @override String files({required Object files}) => 'Αρχεία: ${files}'; + @override String size({required Object size}) => 'Μέγεθος: ${size}'; +} + +// Path: sendTab.picker +class _StringsSendTabPickerEl extends _StringsSendTabPickerEn { + _StringsSendTabPickerEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get file => 'Αρχείο'; + @override String get folder => 'Φάκελος'; + @override String get media => 'Μέσα'; + @override String get text => 'Κείμενο'; + @override String get app => 'Εφαρμογή'; + @override String get clipboard => 'Επικόλληση'; +} + +// Path: sendTab.sendModes +class _StringsSendTabSendModesEl extends _StringsSendTabSendModesEn { + _StringsSendTabSendModesEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get single => 'Ένας παραλήπτης'; + @override String get multiple => 'Πολλαπλοί παραλήπτες'; + @override String get link => 'Διαμοιρασμός μέσω συνδέσμου'; +} + +// Path: settingsTab.general +class _StringsSettingsTabGeneralEl extends _StringsSettingsTabGeneralEn { + _StringsSettingsTabGeneralEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Γενικά'; + @override String get brightness => 'Θέμα'; + @override late final _StringsSettingsTabGeneralBrightnessOptionsEl brightnessOptions = _StringsSettingsTabGeneralBrightnessOptionsEl._(_root); + @override String get color => 'Χρώμα'; + @override late final _StringsSettingsTabGeneralColorOptionsEl colorOptions = _StringsSettingsTabGeneralColorOptionsEl._(_root); + @override String get language => 'Γλώσσα'; + @override late final _StringsSettingsTabGeneralLanguageOptionsEl languageOptions = _StringsSettingsTabGeneralLanguageOptionsEl._(_root); + @override String get saveWindowPlacement => 'Έξοδος: Αποθήκευση θέσης παραθύρου'; + @override String get minimizeToTray => 'Έξοδος: Ελαχιστοποίηση στη γραμμή εργασιών/μενού'; + @override String get launchAtStartup => 'Αυτόματη εκκίνηση μετά τη σύνδεση'; + @override String get launchMinimized => 'Αυτόματη εκκίνηση: Έναρξη ελαχιστοποιημένο'; + @override String get animations => 'Οπτικά εφέ'; +} + +// Path: settingsTab.receive +class _StringsSettingsTabReceiveEl extends _StringsSettingsTabReceiveEn { + _StringsSettingsTabReceiveEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Λήψη'; + @override String get quickSave => '${_root.general.quickSave}'; + @override String get destination => 'Προορισμός'; + @override String get downloads => '(Λήψεις)'; + @override String get saveToGallery => 'Αποθήκευση μέσου στη συλλογή'; + @override String get saveToHistory => 'Αποθήκευση στο ιστορικό'; +} + +// Path: settingsTab.network +class _StringsSettingsTabNetworkEl extends _StringsSettingsTabNetworkEn { + _StringsSettingsTabNetworkEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Δίκτυο'; + @override String get needRestart => 'Κάντε επανεκκίνηση του διακομιστή για να εφαρμοστούν οι ρυθμίσεις!'; + @override String get server => 'Διακομιστής'; + @override String get alias => 'Όνομα συσκευής'; + @override String get deviceType => 'Τύπος συσκευής'; + @override String get deviceModel => 'Μοντέλο συσκευής'; + @override String get port => 'Θύρα'; + @override String portWarning({required Object defaultPort}) => 'Ενδέχεται να μην εντοπιστείτε από άλλες συσκευές επειδή χρησιμοποιείτε μια προσαρμοσμένη θύρα. (προεπιλογή: ${defaultPort})'; + @override String get encryption => 'Κρυπτογράφηση'; + @override String get multicastGroup => 'Αναμετάδοση'; + @override String multicastGroupWarning({required Object defaultMulticast}) => 'Ενδέχεται να μην εντοπιστείτε από άλλες συσκευές επειδή χρησιμοποιείτε μια προσαρμοσμένη διεύθυνση αναμετάδοσης. (προεπιλογή: ${defaultMulticast})'; +} + +// Path: troubleshootPage.firewall +class _StringsTroubleshootPageFirewallEl extends _StringsTroubleshootPageFirewallEn { + _StringsTroubleshootPageFirewallEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get symptom => 'Αυτή η εφαρμογή μπορεί να στείλει αρχεία σε άλλες συσκευές, αλλά άλλες συσκευές δεν μπορούν να στείλουν αρχεία σε αυτήν τη συσκευή.'; + @override String solution({required Object port}) => 'Αυτό είναι πιθανότατα ένα ζήτημα του τείχους προστασίας. Μπορείτε να το λύσετε επιτρέποντας τις εισερχόμενες συνδέσεις (UDP και TCP) στη θύρα ${port}.'; + @override String get openFirewall => 'Άνοιγμα Τείχους Προστασίας'; +} + +// Path: troubleshootPage.noConnection +class _StringsTroubleshootPageNoConnectionEl extends _StringsTroubleshootPageNoConnectionEn { + _StringsTroubleshootPageNoConnectionEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get symptom => 'Και οι δύο συσκευές δεν μπορούν να ανακαλύψουν η μία την άλλη ούτε μπορούν να μοιραστούν αρχεία.'; + @override String get solution => 'Υπάρχει το πρόβλημα και από τις δύο πλευρές; Πρέπει να βεβαιωθείτε ότι και οι δύο συσκευές βρίσκονται στο ίδιο δίκτυο Wi-Fi και μοιράζονται την ίδια διαμόρφωση (θύρα, διεύθυνση αναμετάδοσης, κρυπτογράφηση). Το wifi ενδέχεται να μην επιτρέπει την επικοινωνία μεταξύ των συμμετεχόντων. Σε αυτήν την περίπτωση, αυτή η επιλογή πρέπει να είναι ενεργοποιημένη στο δρομολογητή.'; +} + +// Path: receiveHistoryPage.entryActions +class _StringsReceiveHistoryPageEntryActionsEl extends _StringsReceiveHistoryPageEntryActionsEn { + _StringsReceiveHistoryPageEntryActionsEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get open => 'Άνοιγμα αρχείου'; + @override String get info => 'Πληροφορίες'; + @override String get deleteFromHistory => 'Διαγραφή από το ιστορικό'; +} + +// Path: progressPage.total +class _StringsProgressPageTotalEl extends _StringsProgressPageTotalEn { + _StringsProgressPageTotalEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override late final _StringsProgressPageTotalTitleEl title = _StringsProgressPageTotalTitleEl._(_root); + @override String count({required Object curr, required Object n}) => 'Αρχεία: ${curr} / ${n}'; + @override String size({required Object curr, required Object n}) => 'Μέγεθος: ${curr} / ${n}'; + @override String speed({required Object speed}) => 'Ταχύτητα: ${speed}/s'; +} + +// Path: dialogs.addFile +class _StringsDialogsAddFileEl extends _StringsDialogsAddFileEn { + _StringsDialogsAddFileEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Προσθήκη στις επιλογές'; + @override String get content => 'Τι θέλετε να προστεθεί;'; +} + +// Path: dialogs.addressInput +class _StringsDialogsAddressInputEl extends _StringsDialogsAddressInputEn { + _StringsDialogsAddressInputEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Εισαγωγή διεύθυνσης'; + @override String get hashtag => 'Hashtag'; + @override String get ip => 'Διεύθυνση IP'; + @override String get recentlyUsed => 'Χρησιμοποιήθηκε πρόσφατα: '; +} + +// Path: dialogs.cancelSession +class _StringsDialogsCancelSessionEl extends _StringsDialogsCancelSessionEn { + _StringsDialogsCancelSessionEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Ακύρωση της μεταφοράς του αρχείου'; + @override String get content => 'Θέλετε σίγουρα να ακυρωθεί η μεταφορά του αρχείου?'; +} + +// Path: dialogs.cannotOpenFile +class _StringsDialogsCannotOpenFileEl extends _StringsDialogsCannotOpenFileEn { + _StringsDialogsCannotOpenFileEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Δεν μπορεί να ανοιχτεί το αρχείο'; + @override String content({required Object file}) => 'Δεν μπορεί να ανοιχτεί το "${file}". Έχετε μήπως μετακινήσει, μενονομάσει ή διαγράψει το αρχείο;'; +} + +// Path: dialogs.encryptionDisabledNotice +class _StringsDialogsEncryptionDisabledNoticeEl extends _StringsDialogsEncryptionDisabledNoticeEn { + _StringsDialogsEncryptionDisabledNoticeEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Η κρυπτογράφηση απενεργοποιήθηκε'; + @override String get content => 'Η επικοινωνία πραγματοποιείται πλέον μέσω του μη κρυπτογραφημένου πρωτοκόλλου HTTP. Για να χρησιμοποιήσετε το HTTPS, ενεργοποιήστε ξανά την κρυπτογράφηση.'; +} + +// Path: dialogs.errorDialog +class _StringsDialogsErrorDialogEl extends _StringsDialogsErrorDialogEn { + _StringsDialogsErrorDialogEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => '${_root.general.error}'; +} + +// Path: dialogs.favoriteDialog +class _StringsDialogsFavoriteDialogEl extends _StringsDialogsFavoriteDialogEn { + _StringsDialogsFavoriteDialogEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Αγαπημένα'; + @override String get noFavorites => 'Καμία αγαπημένη συσκευή προς το παρόν.'; + @override String get addFavorite => 'Προσθήκη'; +} + +// Path: dialogs.favoriteDeleteDialog +class _StringsDialogsFavoriteDeleteDialogEl extends _StringsDialogsFavoriteDeleteDialogEn { + _StringsDialogsFavoriteDeleteDialogEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Διαγραφή από τα αγαπημένα'; + @override String content({required Object name}) => 'Θέλετε σίγουρα να διαγραφεί από τα αγαπημένα το "${name}"?'; +} + +// Path: dialogs.favoriteEditDialog +class _StringsDialogsFavoriteEditDialogEl extends _StringsDialogsFavoriteEditDialogEn { + _StringsDialogsFavoriteEditDialogEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get titleAdd => 'Προσθήκη στα αγαπημένα'; + @override String get titleEdit => 'Ρυθμίσεις'; + @override String get name => 'Όνομα συσκευής'; + @override String get auto => '(αυτόματα)'; + @override String get ip => 'Διεύθυνση IP'; + @override String get port => 'Θύρα'; +} + +// Path: dialogs.fileInfo +class _StringsDialogsFileInfoEl extends _StringsDialogsFileInfoEn { + _StringsDialogsFileInfoEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Πληροφορίες αρχείου'; + @override String get fileName => 'Όνομα αρχείου:'; + @override String get path => 'Μονοπάτι:'; + @override String get size => 'Μέγεθος:'; + @override String get sender => 'Αποστολέας:'; + @override String get time => 'Ώρα:'; +} + +// Path: dialogs.fileNameInput +class _StringsDialogsFileNameInputEl extends _StringsDialogsFileNameInputEn { + _StringsDialogsFileNameInputEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Εισάγετε το όνομα του αρχείου'; + @override String original({required Object original}) => 'Πρωτότυπο: ${original}'; +} + +// Path: dialogs.historyClearDialog +class _StringsDialogsHistoryClearDialogEl extends _StringsDialogsHistoryClearDialogEn { + _StringsDialogsHistoryClearDialogEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Καθαρισμός ιστορικού'; + @override String get content => 'Θέλετε σίγουρα να διαγράψετε όλο το ιστορικό;'; +} + +// Path: dialogs.localNetworkUnauthorized +class _StringsDialogsLocalNetworkUnauthorizedEl extends _StringsDialogsLocalNetworkUnauthorizedEn { + _StringsDialogsLocalNetworkUnauthorizedEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => '${_root.dialogs.noPermission.title}'; + @override String get description => 'LocalSend can\'t find other devices without having the permission to scan the local network. Please grant this permission in the settings.'; + @override String get gotoSettings => 'Ρυθμίσεις'; +} + +// Path: dialogs.messageInput +class _StringsDialogsMessageInputEl extends _StringsDialogsMessageInputEn { + _StringsDialogsMessageInputEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Τύπος μηνύματος'; + @override String get multiline => 'Πολλαπλών γραμμών'; +} + +// Path: dialogs.noFiles +class _StringsDialogsNoFilesEl extends _StringsDialogsNoFilesEn { + _StringsDialogsNoFilesEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Κανένα αρχείο δεν επιλέχθηκε'; + @override String get content => 'Παρακαλώ επιλέξτε τουλάχιστον ένα αρχείο.'; +} + +// Path: dialogs.noPermission +class _StringsDialogsNoPermissionEl extends _StringsDialogsNoPermissionEn { + _StringsDialogsNoPermissionEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Χωρίς άδεια'; + @override String get content => 'Δεν έχετε παραχωρήσει τις απαραίτητες άδειες. Παρακαλώ παραχωρήστε τα στις ρυθμίσεις.'; +} + +// Path: dialogs.notAvailableOnPlatform +class _StringsDialogsNotAvailableOnPlatformEl extends _StringsDialogsNotAvailableOnPlatformEn { + _StringsDialogsNotAvailableOnPlatformEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Μη διαθέσιμο'; + @override String get content => 'Αυτό το χαρακτηριστικό είναι διαθέσιμο μόνο σε:'; +} + +// Path: dialogs.qr +class _StringsDialogsQrEl extends _StringsDialogsQrEn { + _StringsDialogsQrEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Κώδικας QR'; +} + +// Path: dialogs.quickActions +class _StringsDialogsQuickActionsEl extends _StringsDialogsQuickActionsEn { + _StringsDialogsQuickActionsEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Γρήγορες Ενέργειες'; + @override String get counter => 'Μετρητής'; + @override String get prefix => 'Πρόθεμα'; + @override String get padZero => 'Συμπλήρωση με μηδενικά'; + @override String get sortBeforeCount => 'Ταξινόμηση αλφαβητικά εκ των προτέρων'; + @override String get random => 'Τυχαία'; +} + +// Path: dialogs.quickSaveNotice +class _StringsDialogsQuickSaveNoticeEl extends _StringsDialogsQuickSaveNoticeEn { + _StringsDialogsQuickSaveNoticeEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => '${_root.general.quickSave}'; + @override String get content => 'Τα αιτήματα αρχείων γίνονται αυτόματα δεκτά. Έχετε υπόψη σας ότι όλοι στο τοπικό δίκτυο μπορούν να σας στείλουν αρχεία.'; +} + +// Path: dialogs.sendModeHelp +class _StringsDialogsSendModeHelpEl extends _StringsDialogsSendModeHelpEn { + _StringsDialogsSendModeHelpEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get title => 'Λειτουργίες αποστολής'; + @override String get single => 'Στέλνει αρχεία σε έναν παραλήπτη. Η επιλογή θα διαγραφεί μετά την ολοκλήρωση της μεταφοράς του αρχείου.'; + @override String get multiple => 'Στέλνει αρχεία σε πολλούς παραλήπτες. Η επιλογή δεν θα διαγραφεί.'; + @override String get link => 'Οι παραλήπτες που δεν έχουν εγκαταστήσει το LocalSend μπορούν να πραγματοποιήσουν λήψη των επιλεγμένων αρχείων ανοίγοντας τον σύνδεσμο στον φυλλομετρητή τους.'; +} + +// Path: settingsTab.general.brightnessOptions +class _StringsSettingsTabGeneralBrightnessOptionsEl extends _StringsSettingsTabGeneralBrightnessOptionsEn { + _StringsSettingsTabGeneralBrightnessOptionsEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get system => 'Σύστημα'; + @override String get dark => 'Σκοτεινό'; + @override String get light => 'Φωτεινό'; +} + +// Path: settingsTab.general.colorOptions +class _StringsSettingsTabGeneralColorOptionsEl extends _StringsSettingsTabGeneralColorOptionsEn { + _StringsSettingsTabGeneralColorOptionsEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get system => 'Σύστημα'; + @override String get oled => 'OLED'; +} + +// Path: settingsTab.general.languageOptions +class _StringsSettingsTabGeneralLanguageOptionsEl extends _StringsSettingsTabGeneralLanguageOptionsEn { + _StringsSettingsTabGeneralLanguageOptionsEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String get system => 'Σύστημα'; +} + +// Path: progressPage.total.title +class _StringsProgressPageTotalTitleEl extends _StringsProgressPageTotalTitleEn { + _StringsProgressPageTotalTitleEl._(_StringsEl root) : this._root = root, super._(root); + + @override final _StringsEl _root; // ignore: unused_field + + // Translations + @override String sending({required Object time}) => 'Συνολική πρόοδος (${time})'; + @override String get finishedError => 'Ολοκληρώθηκε με σφάλμα'; + @override String get canceledSender => 'Ακυρώθηκε από τον αποστολέα'; + @override String get canceledReceiver => 'Ακυρώθηκε από τον παραλήπτη'; +} diff --git a/app/lib/gen/strings_fil_PH.g.dart b/app/lib/gen/strings_fil_PH.g.dart index ae9ec17c971..ac7e5afc820 100644 --- a/app/lib/gen/strings_fil_PH.g.dart +++ b/app/lib/gen/strings_fil_PH.g.dart @@ -63,7 +63,7 @@ class _StringsGeneralFilPh extends _StringsGeneralEn { @override String get copy => 'Kopyahin'; @override String get copiedToClipboard => 'Kopyahin sa Clipboard'; @override String get decline => 'Tanggihan'; - @override String get done => 'Tapusin'; + @override String get done => 'Tapos Na'; @override String get delete => 'Tanggalin'; @override String get edit => 'Baguhin'; @override String get error => 'Error'; @@ -112,7 +112,7 @@ class _StringsSendTabFilPh extends _StringsSendTabEn { @override String get title => 'Magpadala'; @override late final _StringsSendTabSelectionFilPh selection = _StringsSendTabSelectionFilPh._(_root); @override late final _StringsSendTabPickerFilPh picker = _StringsSendTabPickerFilPh._(_root); - @override String get shareIntentInfo => 'Maaring gamitin ang "Share" feature sa iyong mobile device para sa mas madaling pagpili ng mga files.'; + @override String get shareIntentInfo => 'Maaring gamitin ang "Share" feature sa iyong mobile device para sa mas madaling pagpili ng mga file.'; @override String get nearbyDevices => 'Malalapit na mga device'; @override String get thisDevice => 'Ang Device na Ito'; @override String get scan => 'Maghanap ng mga device'; @@ -201,8 +201,8 @@ class _StringsReceivePageFilPh extends _StringsReceivePageEn { other: 'ay gustong magpadala sa iyo ng ${n} na mga file.', ); @override String get subTitleMessage => 'ay nagpadala sa iyo ng mensahe:'; - @override String get subTitleLink => 'ay nagpadala sa iyo ng likn:'; - @override String get canceled => 'Ang sender ay nag-kansela ng request.'; + @override String get subTitleLink => 'ay nagpadala sa iyo ng link:'; + @override String get canceled => 'Ang sender ay nagkansela ng request.'; } // Path: receiveOptionsPage @@ -240,7 +240,7 @@ class _StringsProgressPageFilPh extends _StringsProgressPageEn { // Translations @override String get titleSending => 'Nagpapadala ng mga file'; @override String get titleReceiving => 'Tumatanggap ng mga file'; - @override String get savedToGallery => 'Naka-Save sa Photos'; + @override String get savedToGallery => 'Naka-save sa Photos'; @override late final _StringsProgressPageTotalFilPh total = _StringsProgressPageTotalFilPh._(_root); } @@ -251,10 +251,10 @@ class _StringsWebSharePageFilPh extends _StringsWebSharePageEn { @override final _StringsFilPh _root; // ignore: unused_field // Translations - @override String get title => 'I-Share gamit ang link'; + @override String get title => 'I-share gamit ang link'; @override String get loading => 'Binubuksan ang server...'; @override String get stopping => 'Ihinihinto ang server...'; - @override String get error => 'May nangyaring error habang buksan ang server.'; + @override String get error => 'May nangyaring error habang binubuksan ang server.'; @override String openLink({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('fil'))(n, one: 'Buksan ang link na ito sa browser:', other: 'Buksan ang isa sa mga link na ito sa browser:', @@ -404,7 +404,7 @@ class _StringsTrayFilPh extends _StringsTrayEn { // Translations @override String get open => '${_root.general.open}'; - @override String get close => 'Quit LocalSend'; + @override String get close => 'Isara ang LocalSend'; } // Path: web @@ -440,11 +440,11 @@ class _StringsAssetPickerFilPh extends _StringsAssetPickerEn { @override String get unSupportedAssetType => 'Hindi suportadong file type.'; @override String get unableToAccessAll => 'Hindi ma-access ang lahat ng mga file sa device'; @override String get viewingLimitedAssetsTip => 'Makikita lamang ang mga file at mga album na accessible sa app'; - @override String get changeAccessibleLimitedAssets => 'I-Click para i-update ang accessible na mga file'; + @override String get changeAccessibleLimitedAssets => 'I-click para i-update ang accessible na mga file'; @override String get accessAllTip => 'Ang app na ito ay kaya lamang mag-access ng iilang mga file sa device. Magtungo sa system settings at i-allow ang app para ma-access ang lahat ng media sa device.'; @override String get goToSystemSettings => 'Magpunta sa system settings'; @override String get accessLimitedAssets => 'Ituloy nang limitadong access'; - @override String get accessiblePathName => 'Accessible na mga files'; + @override String get accessiblePathName => 'Accessible na mga file'; @override String get sTypeAudioLabel => 'Audio'; @override String get sTypeImageLabel => 'Image'; @override String get sTypeVideoLabel => 'Video'; @@ -523,9 +523,9 @@ class _StringsSettingsTabGeneralFilPh extends _StringsSettingsTabGeneralEn { @override late final _StringsSettingsTabGeneralColorOptionsFilPh colorOptions = _StringsSettingsTabGeneralColorOptionsFilPh._(_root); @override String get language => 'Wika'; @override late final _StringsSettingsTabGeneralLanguageOptionsFilPh languageOptions = _StringsSettingsTabGeneralLanguageOptionsFilPh._(_root); - @override String get saveWindowPlacement => 'Quit: I-Save ang window placement'; + @override String get saveWindowPlacement => 'Quit: I-save ang window placement'; @override String get minimizeToTray => 'Quit: Paliitin sa Tray/Menu Bar'; - @override String get launchAtStartup => 'I-Autostart pagkatapos mag-login'; + @override String get launchAtStartup => 'I-autostart pagkatapos mag-login'; @override String get launchMinimized => 'Autostart: I-start nang nakatago'; @override String get animations => 'Animations'; } @@ -541,8 +541,8 @@ class _StringsSettingsTabReceiveFilPh extends _StringsSettingsTabReceiveEn { @override String get quickSave => '${_root.general.quickSave}'; @override String get destination => 'Patutunguhan'; @override String get downloads => '(Downloads)'; - @override String get saveToGallery => 'I-Save ang media sa gallery'; - @override String get saveToHistory => 'I-Save sa history'; + @override String get saveToGallery => 'I-save ang media sa gallery'; + @override String get saveToHistory => 'I-save sa history'; } // Path: settingsTab.network @@ -553,7 +553,7 @@ class _StringsSettingsTabNetworkFilPh extends _StringsSettingsTabNetworkEn { // Translations @override String get title => 'Network'; - @override String get needRestart => 'I-Restart ang server para i-apply ang settings!'; + @override String get needRestart => 'I-restart ang server para i-apply ang settings!'; @override String get server => 'Server'; @override String get alias => 'Alias'; @override String get deviceType => 'Device type'; @@ -572,8 +572,8 @@ class _StringsTroubleshootPageFirewallFilPh extends _StringsTroubleshootPageFire @override final _StringsFilPh _root; // ignore: unused_field // Translations - @override String get symptom => 'Ang app na ito ay nakakapag-padala ng mga file sa ibang devices ngunit ang ibang devices ay hindi makapag-padala sa device na ito.'; - @override String solution({required Object port}) => 'Ito ay kadalasang isyu sa firewall. Maari mo maayos sa pamamagitan nang pag-allow ng mga incoming connections (UDP at TCP) sa port ${port}.'; + @override String get symptom => 'Ang app na ito ay nakakapagpadala ng mga file sa ibang devices ngunit ang ibang devices ay hindi makapagpadala sa device na ito.'; + @override String solution({required Object port}) => 'Ito ay kadalasang isyu sa firewall. Maari mong maayos ito sa pamamagitan nang pag-allow ng mga incoming connections (UDP at TCP) sa port ${port}.'; @override String get openFirewall => 'Buksan ang Firewall'; } @@ -584,7 +584,7 @@ class _StringsTroubleshootPageNoConnectionFilPh extends _StringsTroubleshootPage @override final _StringsFilPh _root; // ignore: unused_field // Translations - @override String get symptom => 'Ang dalawa o higit pang devices ay hindi mo discover ang isa\'t isa o hindi makapag-share ng files.'; + @override String get symptom => 'Ang dalawa o higit pang devices ay hindi mo discover ang isa\'t isa o hindi makapag-share ng mga file.'; @override String get solution => 'Ang problema ay nangyayari sa dalawang device? Mangyaring siguraduhin na ang dalawang device ay nasa parehas na wifi network at mayroong parehas na configuration (port, multicast address, encryption). Maaring ang wifi ay hindi pinahihintulutan and komunikasyon sa pagitan nang mga participants. Sa ganitong pangyayari, ang option na ito ay dapat i-enable sa router.'; } @@ -667,7 +667,7 @@ class _StringsDialogsEncryptionDisabledNoticeFilPh extends _StringsDialogsEncryp // Translations @override String get title => 'Ang encryption ay naka-disable'; - @override String get content => 'Ang communication ay nangyayari ngayon gamit ang unencrypted HTTP protocol. Para gamitin ang HTTPS, muling i-enable ang encryption.'; + @override String get content => 'Ang communication ngayon ay nangyayari gamit ang unencrypted HTTP protocol. Para gamitin ang HTTPS, muling i-enable ang encryption.'; } // Path: dialogs.errorDialog @@ -763,7 +763,7 @@ class _StringsDialogsLocalNetworkUnauthorizedFilPh extends _StringsDialogsLocalN // Translations @override String get title => '${_root.dialogs.noPermission.title}'; - @override String get description => 'Hindi makikita ng LocalSend ang ibang devices hangga\'t hindi nabibigyan ng permission para mag scan sa lokal na network. Mangyaring bigyan ito ng permission sa settings.'; + @override String get description => 'Hindi makikita ng LocalSend ang ibang devices hangga\'t hindi nabibigyan ng permission para mag-scan sa lokal na network. Mangyaring bigyan ito ng permission sa settings.'; @override String get gotoSettings => 'Settings'; } @@ -774,7 +774,7 @@ class _StringsDialogsMessageInputFilPh extends _StringsDialogsMessageInputEn { @override final _StringsFilPh _root; // ignore: unused_field // Translations - @override String get title => 'I-Type ang message'; + @override String get title => 'I-type ang message'; @override String get multiline => 'Multiline'; } @@ -844,7 +844,7 @@ class _StringsDialogsQuickSaveNoticeFilPh extends _StringsDialogsQuickSaveNotice // Translations @override String get title => '${_root.general.quickSave}'; - @override String get content => 'Ang mga file request ay awtomatikong tinatanggap. Mabatid lamang na ang lahat ng nasa lokal na network ay maaaring mag-padala sa iyo ng mga file.'; + @override String get content => 'Ang mga file request ay awtomatikong tinatanggap. Mabatid lamang na ang lahat ng nasa lokal na network ay maaaring magpadala sa iyo ng mga file.'; } // Path: dialogs.sendModeHelp @@ -857,7 +857,7 @@ class _StringsDialogsSendModeHelpFilPh extends _StringsDialogsSendModeHelpEn { @override String get title => 'Send modes'; @override String get single => 'Magpadala ng mga file sa iisang recipient o tatanggap. Ang mga pagpipilian ay maaalis pagkatapos ipadala ang file.'; @override String get multiple => 'Magpadala ng mga file sa maraming recipient o tatanggap. Ang mga pagpipilian ay hindi maaalis.'; - @override String get link => 'Ang mga recipient o tatanggap na walang nakainstall na LocalSend ay maaring mag download nang mga napiling files sa pamamagitan ng pagbukas ng link sa kanilang browser.'; + @override String get link => 'Ang mga recipient o tatanggap na walang nakainstall na LocalSend ay maaring mag download nang mga napiling file sa pamamagitan ng pagbukas ng link sa kanilang browser.'; } // Path: settingsTab.general.brightnessOptions @@ -900,7 +900,7 @@ class _StringsProgressPageTotalTitleFilPh extends _StringsProgressPageTotalTitle @override final _StringsFilPh _root; // ignore: unused_field // Translations - @override String sending({required Object time}) => 'Kabuuang progress (${time})'; + @override String sending({required Object time}) => 'Kabuuang progreso (${time})'; @override String get finishedError => 'Natapos nang may error'; @override String get canceledSender => 'Kinansela ng sender'; @override String get canceledReceiver => 'Kinansela ng receiver'; diff --git a/app/lib/gen/strings_pl.g.dart b/app/lib/gen/strings_pl.g.dart index 701ad616ff5..92271144630 100644 --- a/app/lib/gen/strings_pl.g.dart +++ b/app/lib/gen/strings_pl.g.dart @@ -439,7 +439,7 @@ class _StringsSettingsTabGeneralPl extends _StringsSettingsTabGeneralEn { // Translations @override String get title => 'Ogólne'; - @override String get brightness => 'Jasność'; + @override String get brightness => 'Motyw'; @override late final _StringsSettingsTabGeneralBrightnessOptionsPl brightnessOptions = _StringsSettingsTabGeneralBrightnessOptionsPl._(_root); @override String get color => 'Kolor'; @override late final _StringsSettingsTabGeneralColorOptionsPl colorOptions = _StringsSettingsTabGeneralColorOptionsPl._(_root); diff --git a/app/macos/Runner/Info.plist b/app/macos/Runner/Info.plist index 84f13ff8555..3d49f836fc1 100644 --- a/app/macos/Runner/Info.plist +++ b/app/macos/Runner/Info.plist @@ -44,6 +44,7 @@ cs de en + el es-ES eu fa diff --git a/app/pubspec.yaml b/app/pubspec.yaml index a0e27db89d7..f55d06690ba 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -102,7 +102,7 @@ msix_config: # publisher: CN=0A8E9755-183F-4F0B-823F-1B8C991D7B97 identity_name: 11157TienDoNam.LocalSend logo_path: assets\img\logo-512.png - languages: en, ar, bn, cs, de, es-ES, eu, fa, fr-FR, he, hu, in, it, ja, ko, ne, nl, pl, pt-BR, ru, sv, th, tr, uk, vi, zh-CN, zh-HK, zh-TW + languages: en, ar, bn, cs, de, el, es-ES, eu, fa, fr-FR, he, hu, in, it, ja, ko, ne, nl, pl, pt-BR, ru, sv, th, tr, uk, vi, zh-CN, zh-HK, zh-TW # https://github.com/localsend/localsend/issues/398 os_min_version: 10.0.19041.0 From 770dff956bdb49782b57bf61780804987f26ad3a Mon Sep 17 00:00:00 2001 From: Tien Do Nam Date: Fri, 17 Nov 2023 22:19:42 +0100 Subject: [PATCH 18/31] i18n: regenerate --- app/assets/i18n/_missing_translations_ar.json | 41 +----- app/assets/i18n/_missing_translations_ca.json | 4 +- app/assets/i18n/_missing_translations_fa.json | 28 +--- app/assets/i18n/_missing_translations_id.json | 4 +- app/assets/i18n/_missing_translations_km.json | 4 +- app/assets/i18n/_missing_translations_ne.json | 4 +- app/assets/i18n/_missing_translations_pl.json | 41 +----- app/assets/i18n/_missing_translations_sv.json | 4 +- app/assets/i18n/_missing_translations_ur.json | 4 +- app/assets/i18n/strings_ar.i18n.json | 33 ++++- app/assets/i18n/strings_bn.i18n.json | 132 +++++++++--------- app/assets/i18n/strings_ca.i18n.json | 2 +- app/assets/i18n/strings_cs.i18n.json | 2 +- app/assets/i18n/strings_de.i18n.json | 2 +- app/assets/i18n/strings_el.i18n.json | 4 +- app/assets/i18n/strings_es-ES.i18n.json | 2 +- app/assets/i18n/strings_eu.i18n.json | 2 +- app/assets/i18n/strings_fa.i18n.json | 24 +++- app/assets/i18n/strings_fr-FR.i18n.json | 2 +- app/assets/i18n/strings_he.i18n.json | 2 +- app/assets/i18n/strings_hu.i18n.json | 2 +- app/assets/i18n/strings_id.i18n.json | 2 +- app/assets/i18n/strings_it.i18n.json | 2 +- app/assets/i18n/strings_ja.i18n.json | 2 +- app/assets/i18n/strings_km.i18n.json | 2 +- app/assets/i18n/strings_ko.i18n.json | 2 +- app/assets/i18n/strings_ne.i18n.json | 2 +- app/assets/i18n/strings_nl.i18n.json | 2 +- app/assets/i18n/strings_pl.i18n.json | 33 ++++- app/assets/i18n/strings_pt-BR.i18n.json | 2 +- app/assets/i18n/strings_ru.i18n.json | 2 +- app/assets/i18n/strings_sv.i18n.json | 2 +- app/assets/i18n/strings_th.i18n.json | 2 +- app/assets/i18n/strings_tr.i18n.json | 2 +- app/assets/i18n/strings_uk.i18n.json | 2 +- app/assets/i18n/strings_ur.i18n.json | 2 +- app/assets/i18n/strings_zh-CN.i18n.json | 2 +- app/assets/i18n/strings_zh-TW.i18n.json | 2 +- app/lib/gen/strings.g.dart | 2 +- app/lib/gen/strings_ar.g.dart | 57 ++++++++ app/lib/gen/strings_fa.g.dart | 54 +++++++ app/lib/gen/strings_pl.g.dart | 57 ++++++++ 42 files changed, 357 insertions(+), 221 deletions(-) diff --git a/app/assets/i18n/_missing_translations_ar.json b/app/assets/i18n/_missing_translations_ar.json index 3f88e5682d3..69291e3d5d6 100644 --- a/app/assets/i18n/_missing_translations_ar.json +++ b/app/assets/i18n/_missing_translations_ar.json @@ -2,44 +2,5 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=ar' to quickly apply the newly added translations." - ], - "general": { - "delete": "حذف", - "noItemInClipboard": "لا توجد عناصر في الحافظة" - }, - "sendTab": { - "picker": { - "clipboard": "لصق" - } - }, - "settingsTab": { - "general": { - "colorOptions": { - "oled": "OLED" - } - } - }, - "dialogs": { - "favoriteDialog": { - "title": "المفضلة", - "noFavorites": "لا توجد أجهزة مفضلة بعد.", - "addFavorite": "إضافة" - }, - "favoriteDeleteDialog": { - "title": "حذف من المفضلة", - "content": "هل ترغب حقًا في حذف \"{name}\" من قائمة المفضلة؟" - }, - "favoriteEditDialog": { - "titleAdd": "إضافة إلى المفضلة", - "titleEdit": "تعديل", - "name": "الاسم", - "auto": "(تلقائي)", - "ip": "عنوان IP", - "port": "Port" - }, - "historyClearDialog": { - "title": "محو السجل", - "content": "هل ترغب حقًا في محو السجل بالكامل؟" - } - } + ] } diff --git a/app/assets/i18n/_missing_translations_ca.json b/app/assets/i18n/_missing_translations_ca.json index bb6a63e1670..0f6208739a5 100644 --- a/app/assets/i18n/_missing_translations_ca.json +++ b/app/assets/i18n/_missing_translations_ca.json @@ -31,8 +31,8 @@ }, "favoriteEditDialog": { "titleAdd": "Add to favorites", - "titleEdit": "Adjustment", - "name": "Alias", + "titleEdit": "Settings", + "name": "Device name", "auto": "(auto)", "ip": "IP Address", "port": "Port" diff --git a/app/assets/i18n/_missing_translations_fa.json b/app/assets/i18n/_missing_translations_fa.json index c527d4eba8f..68c22596fe7 100644 --- a/app/assets/i18n/_missing_translations_fa.json +++ b/app/assets/i18n/_missing_translations_fa.json @@ -2,31 +2,5 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=fa' to quickly apply the newly added translations." - ], - "general": { - "delete": "حذف" - }, - "dialogs": { - "favoriteDialog": { - "title": "علاقه‌مندی‌ها", - "noFavorites": "هنوز دستگاهی اضافه نشده", - "addFavorite": "افزودن" - }, - "favoriteDeleteDialog": { - "title": "حذف از علاقه‌مندی‌ها", - "content": "واقعاً می خواهید از علاقه‌مندی‌ها حذف کنید \"{name}\"?" - }, - "favoriteEditDialog": { - "titleAdd": "افزودن به علاقه‌مندی‌ها", - "titleEdit": "تنظیمات", - "name": "نام مستعار", - "auto": "(خودکار)", - "ip": "آدرس آی پی", - "port": "پورت" - }, - "historyClearDialog": { - "title": "پاکسازی تاریخچه", - "content": "واقعاً می خواهید کل تاریخچه را حذف کنید؟" - } - } + ] } diff --git a/app/assets/i18n/_missing_translations_id.json b/app/assets/i18n/_missing_translations_id.json index 6a8da29a71e..5117770ff8c 100644 --- a/app/assets/i18n/_missing_translations_id.json +++ b/app/assets/i18n/_missing_translations_id.json @@ -31,8 +31,8 @@ }, "favoriteEditDialog": { "titleAdd": "Add to favorites", - "titleEdit": "Adjustment", - "name": "Alias", + "titleEdit": "Settings", + "name": "Device name", "auto": "(auto)", "ip": "IP Address", "port": "Port" diff --git a/app/assets/i18n/_missing_translations_km.json b/app/assets/i18n/_missing_translations_km.json index cde3b650703..e0980f2b4e2 100644 --- a/app/assets/i18n/_missing_translations_km.json +++ b/app/assets/i18n/_missing_translations_km.json @@ -24,8 +24,8 @@ }, "favoriteEditDialog": { "titleAdd": "Add to favorites", - "titleEdit": "Adjustment", - "name": "Alias", + "titleEdit": "Settings", + "name": "Device name", "auto": "(auto)", "ip": "IP Address", "port": "Port" diff --git a/app/assets/i18n/_missing_translations_ne.json b/app/assets/i18n/_missing_translations_ne.json index 3cc8e0e467d..3fec622366e 100644 --- a/app/assets/i18n/_missing_translations_ne.json +++ b/app/assets/i18n/_missing_translations_ne.json @@ -31,8 +31,8 @@ }, "favoriteEditDialog": { "titleAdd": "Add to favorites", - "titleEdit": "Adjustment", - "name": "Alias", + "titleEdit": "Settings", + "name": "Device name", "auto": "(auto)", "ip": "IP Address", "port": "Port" diff --git a/app/assets/i18n/_missing_translations_pl.json b/app/assets/i18n/_missing_translations_pl.json index d701cea9f86..0da0da9af82 100644 --- a/app/assets/i18n/_missing_translations_pl.json +++ b/app/assets/i18n/_missing_translations_pl.json @@ -2,44 +2,5 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=pl' to quickly apply the newly added translations." - ], - "general": { - "delete": "Usuń", - "noItemInClipboard": "Schowek jest pusty" - }, - "sendTab": { - "picker": { - "clipboard": "Wklej" - } - }, - "settingsTab": { - "general": { - "colorOptions": { - "oled": "OLED" - } - } - }, - "dialogs": { - "favoriteDialog": { - "title": "Ulubione", - "noFavorites": "Brak ulubionych urządzeń.", - "addFavorite": "Dodaj" - }, - "favoriteDeleteDialog": { - "title": "Usuń z ulubionych", - "content": "Czy na pewno chcesz usunąć z ulubionych \"{name}\"?" - }, - "favoriteEditDialog": { - "titleAdd": "Dodaj do ulubionych", - "titleEdit": "Dostosuj", - "name": "Alias", - "auto": "(auto)", - "ip": "Adres IP", - "port": "Port" - }, - "historyClearDialog": { - "title": "Wyczyść historię", - "content": "Czy na pewno chcesz usunąć całą historię?" - } - } + ] } diff --git a/app/assets/i18n/_missing_translations_sv.json b/app/assets/i18n/_missing_translations_sv.json index 45ebaa1d1f3..9b3cc3147a3 100644 --- a/app/assets/i18n/_missing_translations_sv.json +++ b/app/assets/i18n/_missing_translations_sv.json @@ -31,8 +31,8 @@ }, "favoriteEditDialog": { "titleAdd": "Add to favorites", - "titleEdit": "Adjustment", - "name": "Alias", + "titleEdit": "Settings", + "name": "Device name", "auto": "(auto)", "ip": "IP Address", "port": "Port" diff --git a/app/assets/i18n/_missing_translations_ur.json b/app/assets/i18n/_missing_translations_ur.json index 3432c2711e5..e46c296f01b 100644 --- a/app/assets/i18n/_missing_translations_ur.json +++ b/app/assets/i18n/_missing_translations_ur.json @@ -31,8 +31,8 @@ }, "favoriteEditDialog": { "titleAdd": "Add to favorites", - "titleEdit": "Adjustment", - "name": "Alias", + "titleEdit": "Settings", + "name": "Device name", "auto": "(auto)", "ip": "IP Address", "port": "Port" diff --git a/app/assets/i18n/strings_ar.i18n.json b/app/assets/i18n/strings_ar.i18n.json index 0ea5ddf8467..9536d154fe6 100644 --- a/app/assets/i18n/strings_ar.i18n.json +++ b/app/assets/i18n/strings_ar.i18n.json @@ -14,6 +14,7 @@ "copiedToClipboard": "نسخ إلى الحافظة", "decline": "ارفض", "done": "انتهى", + "delete": "حذف", "edit": "تعديل", "error": "خطأ", "example": "مثال", @@ -36,7 +37,8 @@ "stop": "قف", "save": "احفظ", "unchanged": "دون تغيير", - "unknown": "مجهول" + "unknown": "مجهول", + "noItemInClipboard": "لا توجد عناصر في الحافظة" }, "receiveTab": { "title": "استلام", @@ -58,7 +60,8 @@ "folder": "مجلد", "media": "وسائط", "text": "نص", - "app": "تطبيق" + "app": "تطبيق", + "clipboard": "لصق" }, "shareIntentInfo": "يمكنك أيضًا استخدام ميزة \"مشاركة\" بجهازك المحمول لتحديد الملفات بسهولة.", "nearbyDevices": "الأجهزة القريبة", @@ -86,7 +89,8 @@ }, "color": "لون", "colorOptions": { - "system": "النظام" + "system": "النظام", + "oled": "OLED" }, "language": "لغة", "languageOptions": { @@ -214,7 +218,7 @@ "changelogPage": { "title": "التغييرات" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "قد تحتوي المناطق المختلفة على كلمات مختلفة ، وقد لا تتطابق 1:1", "adjectives": [ "محبوب", @@ -313,6 +317,23 @@ "errorDialog": { "title": "@:general.error" }, + "favoriteDialog": { + "title": "المفضلة", + "noFavorites": "لا توجد أجهزة مفضلة بعد.", + "addFavorite": "إضافة" + }, + "favoriteDeleteDialog": { + "title": "حذف من المفضلة", + "content": "هل ترغب حقًا في حذف \"{name}\" من قائمة المفضلة؟" + }, + "favoriteEditDialog": { + "titleAdd": "إضافة إلى المفضلة", + "titleEdit": "تعديل", + "name": "الاسم", + "auto": "(تلقائي)", + "ip": "عنوان IP", + "port": "Port" + }, "fileInfo": { "title": "معلومات الملف", "fileName": "اسم الملف:", @@ -325,6 +346,10 @@ "title": "أدخل اسم الملف", "original": "أصلي: {original}" }, + "historyClearDialog": { + "title": "محو السجل", + "content": "هل ترغب حقًا في محو السجل بالكامل؟" + }, "localNetworkUnauthorized": { "title": "@:dialogs.noPermission.title", "description": "لا يمكن ل LocalSend العثور على الأجهزة الأخرى بدون الإذن بفحص الشبكة المحلية. يرجى منح هذا الإذن في الإعدادات.", diff --git a/app/assets/i18n/strings_bn.i18n.json b/app/assets/i18n/strings_bn.i18n.json index 2df2cec804e..569315e2bfc 100644 --- a/app/assets/i18n/strings_bn.i18n.json +++ b/app/assets/i18n/strings_bn.i18n.json @@ -155,7 +155,7 @@ "title": "অ্যাপস (এপিকে)", "excludeSystemApps": "সিস্টেম অ্যাপ বাদ দিন", "excludeAppsWithoutLaunchIntent": "অ-লঞ্চযোগ্য অ্যাপগুলি বাদ দিন", - "apps": "{n} Apps" + "apps": "{n} Apps" }, "selectedFilesPage": { "deleteAll": "সব ডিলিট করুন" @@ -218,84 +218,84 @@ "changelogPage": { "title": "Changelog" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Different locales may have different words, it may not match 1:1", "adjectives": [ "আরাধ্য", - "সুন্দর", - "বড়", - "উজ্জ্বল", - "পরিষ্কার", - "চতুর", - "ঠান্ডা", - "চতুর", - "ধূর্ত", - "নির্ধারিত", - "অনলস", - "দক্ষ", - "অসাধারণ", - "দ্রুত", - "ভালো", - "তাজা", - "ভাল", - "চমৎকার", - "দারুণ", - "সুদর্শন", - "গরম", - "দয়াময়", - "সুন্দর", - "রহস্যময়", - "পরিচ্ছন্ন", - "সুন্দর", - "রোগী", - "সুন্দর", - "ক্ষমতাশালী", - "ধনী", - "গোপন", - "স্মার্ট", - "কঠিন", - "বিশেষ", - "কৌশলগত", - "শক্তিশালী", - "পরিপাটি", - "জ্ঞানী" + "সুন্দর", + "বড়", + "উজ্জ্বল", + "পরিষ্কার", + "চতুর", + "ঠান্ডা", + "চতুর", + "ধূর্ত", + "নির্ধারিত", + "অনলস", + "দক্ষ", + "অসাধারণ", + "দ্রুত", + "ভালো", + "তাজা", + "ভাল", + "চমৎকার", + "দারুণ", + "সুদর্শন", + "গরম", + "দয়াময়", + "সুন্দর", + "রহস্যময়", + "পরিচ্ছন্ন", + "সুন্দর", + "রোগী", + "সুন্দর", + "ক্ষমতাশালী", + "ধনী", + "গোপন", + "স্মার্ট", + "কঠিন", + "বিশেষ", + "কৌশলগত", + "শক্তিশালী", + "পরিপাটি", + "জ্ঞানী" ], "fruits": [ "আপেল", - "অ্যাভোকাডো", - "কলা", - "ব্ল্যাকবেরি", - "ব্লুবেরি", - "ব্রকলি", - "গাজর", - "চেরি", - "নারকেল", - "আঙ্গুর", - "লেবু", - "লেটুস", - "আম", - "তরমুজ", - "মাশরুম", - "পেঁয়াজ", - "কমলা", - "পেঁপে", - "পীচ", - "নাশপাতি", - "আনারস", - "আলু", - "কুমড়া", - "রাস্পবেরি", - "স্ট্রবেরি", - "টমেটো" + "অ্যাভোকাডো", + "কলা", + "ব্ল্যাকবেরি", + "ব্লুবেরি", + "ব্রকলি", + "গাজর", + "চেরি", + "নারকেল", + "আঙ্গুর", + "লেবু", + "লেটুস", + "আম", + "তরমুজ", + "মাশরুম", + "পেঁয়াজ", + "কমলা", + "পেঁপে", + "পীচ", + "নাশপাতি", + "আনারস", + "আলু", + "কুমড়া", + "রাস্পবেরি", + "স্ট্রবেরি", + "টমেটো" ], "combination": "{adjective} {fruit}", "@combination": "In some languages, the adjective must be last." }, "dialogs": { - "historyClearDialog" : { + "historyClearDialog": { "title": "ইতিহাস পরিষ্কার করুন", "content": "আপনি কি সত্যিই সমগ্র ইতিহাস মুছে ফেলতে চান?" - }, + }, "addFile": { "title": "সিলেকশনে যুক্ত করুন", "content": "আপনি কি যোগ করতে চান?" diff --git a/app/assets/i18n/strings_ca.i18n.json b/app/assets/i18n/strings_ca.i18n.json index e57c7aa34d2..8252f5c7493 100644 --- a/app/assets/i18n/strings_ca.i18n.json +++ b/app/assets/i18n/strings_ca.i18n.json @@ -214,7 +214,7 @@ "changelogPage": { "title": "Registre de canvis" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Different locales may have different words, it may not match 1:1", "adjectives": [ "Adorable", diff --git a/app/assets/i18n/strings_cs.i18n.json b/app/assets/i18n/strings_cs.i18n.json index e6f9e3a44dd..6da3efcf4d9 100644 --- a/app/assets/i18n/strings_cs.i18n.json +++ b/app/assets/i18n/strings_cs.i18n.json @@ -218,7 +218,7 @@ "changelogPage": { "title": "Seznam změn" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Inherits from the English version" }, "dialogs": { diff --git a/app/assets/i18n/strings_de.i18n.json b/app/assets/i18n/strings_de.i18n.json index 31c0748d14c..e4ff586f4b4 100644 --- a/app/assets/i18n/strings_de.i18n.json +++ b/app/assets/i18n/strings_de.i18n.json @@ -218,7 +218,7 @@ "changelogPage": { "title": "Changelog" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Inherits from the English version" }, "dialogs": { diff --git a/app/assets/i18n/strings_el.i18n.json b/app/assets/i18n/strings_el.i18n.json index fb54e35976c..851d856ab09 100644 --- a/app/assets/i18n/strings_el.i18n.json +++ b/app/assets/i18n/strings_el.i18n.json @@ -220,8 +220,8 @@ }, "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Different locales may have different words, it may not match 1:1", - "adjectives": [ - "Λατρευτό", + "adjectives": [ + "Λατρευτό", "Πανεμορφο", "Μεγάλο", "Λαμπερό", diff --git a/app/assets/i18n/strings_es-ES.i18n.json b/app/assets/i18n/strings_es-ES.i18n.json index 089dcf112b8..3e3a5a93730 100644 --- a/app/assets/i18n/strings_es-ES.i18n.json +++ b/app/assets/i18n/strings_es-ES.i18n.json @@ -218,7 +218,7 @@ "changelogPage": { "title": "Registro de cambios" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Uses English version" }, "dialogs": { diff --git a/app/assets/i18n/strings_eu.i18n.json b/app/assets/i18n/strings_eu.i18n.json index a485167594e..9419e022a01 100644 --- a/app/assets/i18n/strings_eu.i18n.json +++ b/app/assets/i18n/strings_eu.i18n.json @@ -218,7 +218,7 @@ "changelogPage": { "title": "Aldaketak" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Uses English version" }, "dialogs": { diff --git a/app/assets/i18n/strings_fa.i18n.json b/app/assets/i18n/strings_fa.i18n.json index 2f6464bad96..fb2278ec3e9 100644 --- a/app/assets/i18n/strings_fa.i18n.json +++ b/app/assets/i18n/strings_fa.i18n.json @@ -14,6 +14,7 @@ "copiedToClipboard": "در کلیپ بورد کپی شد", "decline": "نپذیرفتن", "done": "انجام شد", + "delete": "حذف", "edit": "ویرایش", "error": "خطا", "example": "مثال", @@ -217,7 +218,7 @@ "changelogPage": { "title": "تاریخچه تغییرات برنامه" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Different locales may have different words, it may not match 1:1", "adjectives": [ "ستودنی", @@ -316,6 +317,23 @@ "errorDialog": { "title": "@:general.error" }, + "favoriteDialog": { + "title": "علاقه‌مندی‌ها", + "noFavorites": "هنوز دستگاهی اضافه نشده", + "addFavorite": "افزودن" + }, + "favoriteDeleteDialog": { + "title": "حذف از علاقه‌مندی‌ها", + "content": "واقعاً می خواهید از علاقه‌مندی‌ها حذف کنید \"{name}\"?" + }, + "favoriteEditDialog": { + "titleAdd": "افزودن به علاقه‌مندی‌ها", + "titleEdit": "تنظیمات", + "name": "نام مستعار", + "auto": "(خودکار)", + "ip": "آدرس آی پی", + "port": "پورت" + }, "fileInfo": { "title": "مشخصات فایل", "fileName": "نام فایل:", @@ -328,6 +346,10 @@ "title": "نام فایل را وارد کنید", "original": "اصلی: {original}" }, + "historyClearDialog": { + "title": "پاکسازی تاریخچه", + "content": "واقعاً می خواهید کل تاریخچه را حذف کنید؟" + }, "localNetworkUnauthorized": { "title": "@:dialogs.noPermission.title", "description": "لوکال سند نمی تواند دستگاه های دیگر را بدون داشتن مجوز اسکن شبکه محلی پیدا کند. لطفاً این مجوز را در تنظیمات به برنامه بدهید", diff --git a/app/assets/i18n/strings_fr-FR.i18n.json b/app/assets/i18n/strings_fr-FR.i18n.json index c50bebd1f9c..3333cafda6f 100644 --- a/app/assets/i18n/strings_fr-FR.i18n.json +++ b/app/assets/i18n/strings_fr-FR.i18n.json @@ -218,7 +218,7 @@ "changelogPage": { "title": "Historique des mises à jour" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Inherits from the English version" }, "dialogs": { diff --git a/app/assets/i18n/strings_he.i18n.json b/app/assets/i18n/strings_he.i18n.json index 29eba67c44c..651bb67d002 100644 --- a/app/assets/i18n/strings_he.i18n.json +++ b/app/assets/i18n/strings_he.i18n.json @@ -218,7 +218,7 @@ "changelogPage": { "title": "יומן שינויים" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Inherits from the English version" }, "dialogs": { diff --git a/app/assets/i18n/strings_hu.i18n.json b/app/assets/i18n/strings_hu.i18n.json index 6644531b3b5..c366d03d2a1 100644 --- a/app/assets/i18n/strings_hu.i18n.json +++ b/app/assets/i18n/strings_hu.i18n.json @@ -218,7 +218,7 @@ "changelogPage": { "title": "Változásnapló" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Az angol változatból örökölve" }, "dialogs": { diff --git a/app/assets/i18n/strings_id.i18n.json b/app/assets/i18n/strings_id.i18n.json index 5d7d34deb35..4f0990e8862 100644 --- a/app/assets/i18n/strings_id.i18n.json +++ b/app/assets/i18n/strings_id.i18n.json @@ -214,7 +214,7 @@ "changelogPage": { "title": "Catatan Perubahan" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Lokasi yang berbeda mungkin memiliki kata yang berbeda, memungkinkan ketidakcocokan 1:1", "adjectives": [ "Menarik", diff --git a/app/assets/i18n/strings_it.i18n.json b/app/assets/i18n/strings_it.i18n.json index c59a222726b..9e3a4a9ad75 100644 --- a/app/assets/i18n/strings_it.i18n.json +++ b/app/assets/i18n/strings_it.i18n.json @@ -218,7 +218,7 @@ "changelogPage": { "title": "Changelog" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Eredita dalla versione inglese" }, "dialogs": { diff --git a/app/assets/i18n/strings_ja.i18n.json b/app/assets/i18n/strings_ja.i18n.json index 535c8aa109f..5d4435fca30 100644 --- a/app/assets/i18n/strings_ja.i18n.json +++ b/app/assets/i18n/strings_ja.i18n.json @@ -218,7 +218,7 @@ "changelogPage": { "title": "更新履歴" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Inherits from the English version" }, "dialogs": { diff --git a/app/assets/i18n/strings_km.i18n.json b/app/assets/i18n/strings_km.i18n.json index c0ad99317bd..f665d9ac56a 100644 --- a/app/assets/i18n/strings_km.i18n.json +++ b/app/assets/i18n/strings_km.i18n.json @@ -215,7 +215,7 @@ "changelogPage": { "title": "កំណត់ត្រាការផ្លាស់ប្តូរ" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "មូលដ្ឋានផ្សេងគ្នាអាចមានពាក្យផ្សេងគ្នា វាប្រហែលជាមិនត្រូវគ្នានឹង 1:1 ទេ។", "adjectives": [ "គួរអោយស្រលាញ់", diff --git a/app/assets/i18n/strings_ko.i18n.json b/app/assets/i18n/strings_ko.i18n.json index ecea3aa4070..6d238cb8082 100644 --- a/app/assets/i18n/strings_ko.i18n.json +++ b/app/assets/i18n/strings_ko.i18n.json @@ -218,7 +218,7 @@ "changelogPage": { "title": "업데이트 이력" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Inherits from the English version" }, "dialogs": { diff --git a/app/assets/i18n/strings_ne.i18n.json b/app/assets/i18n/strings_ne.i18n.json index db07c034ff4..7483d7fdc08 100644 --- a/app/assets/i18n/strings_ne.i18n.json +++ b/app/assets/i18n/strings_ne.i18n.json @@ -214,7 +214,7 @@ "changelogPage": { "title": "Changelog" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "विभिन्न स्थानहरूमा फरक शब्दहरू हुन सक्छन्, यो 1:1 सँग नमिल्न सक्छ", "adjectives": [ "मनमोहक", diff --git a/app/assets/i18n/strings_nl.i18n.json b/app/assets/i18n/strings_nl.i18n.json index d21137cc242..7d48699b7a5 100644 --- a/app/assets/i18n/strings_nl.i18n.json +++ b/app/assets/i18n/strings_nl.i18n.json @@ -218,7 +218,7 @@ "changelogPage": { "title": "Changelog" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Inherits from the English version" }, "dialogs": { diff --git a/app/assets/i18n/strings_pl.i18n.json b/app/assets/i18n/strings_pl.i18n.json index 3edec824611..9d5b964d02c 100644 --- a/app/assets/i18n/strings_pl.i18n.json +++ b/app/assets/i18n/strings_pl.i18n.json @@ -14,6 +14,7 @@ "copiedToClipboard": "Skopiowane do Schowka", "decline": "Odrzuć", "done": "Gotowe", + "delete": "Usuń", "edit": "Edytuj", "error": "Błąd", "example": "Przykład", @@ -36,7 +37,8 @@ "stop": "Zatrzymaj", "save": "Zapisz", "unchanged": "Bez Zmian", - "unknown": "Nieznany" + "unknown": "Nieznany", + "noItemInClipboard": "Schowek jest pusty" }, "receiveTab": { "title": "Odbierz", @@ -58,7 +60,8 @@ "folder": "Folder", "media": "Media", "text": "Tekst", - "app": "Aplikacja" + "app": "Aplikacja", + "clipboard": "Wklej" }, "shareIntentInfo": "Możesz także skorzystać z funkcji „Udostępnij” swojego urządzenia mobilnego, aby łatwiej wybierać pliki.", "nearbyDevices": "Urządzenia w pobliżu", @@ -86,7 +89,8 @@ }, "color": "Kolor", "colorOptions": { - "system": "System" + "system": "System", + "oled": "OLED" }, "language": "Język", "languageOptions": { @@ -214,7 +218,7 @@ "changelogPage": { "title": "Dziennik Zmian" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Inherits from the English version" }, "dialogs": { @@ -243,6 +247,23 @@ "errorDialog": { "title": "@:general.error" }, + "favoriteDialog": { + "title": "Ulubione", + "noFavorites": "Brak ulubionych urządzeń.", + "addFavorite": "Dodaj" + }, + "favoriteDeleteDialog": { + "title": "Usuń z ulubionych", + "content": "Czy na pewno chcesz usunąć z ulubionych \"{name}\"?" + }, + "favoriteEditDialog": { + "titleAdd": "Dodaj do ulubionych", + "titleEdit": "Dostosuj", + "name": "Alias", + "auto": "(auto)", + "ip": "Adres IP", + "port": "Port" + }, "fileInfo": { "title": "Informacje o pliku", "fileName": "Nazwa pliku:", @@ -255,6 +276,10 @@ "title": "Wpisz imię", "original": "Oryginalny: {original}" }, + "historyClearDialog": { + "title": "Wyczyść historię", + "content": "Czy na pewno chcesz usunąć całą historię?" + }, "localNetworkUnauthorized": { "title": "@:dialogs.noPermission.title", "description": "LocalSend nie może znaleźć innych urządzeń bez uprawnienia do skanowania sieci lokalnej. Udziel tego uprawnienia w ustawieniach.", diff --git a/app/assets/i18n/strings_pt-BR.i18n.json b/app/assets/i18n/strings_pt-BR.i18n.json index 27c72335df0..76b8353d2b2 100644 --- a/app/assets/i18n/strings_pt-BR.i18n.json +++ b/app/assets/i18n/strings_pt-BR.i18n.json @@ -218,7 +218,7 @@ "changelogPage": { "title": "Histórico de alterações" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Different locales may have different words, it may not match 1:1", "adjectives": [ "Adorável", diff --git a/app/assets/i18n/strings_ru.i18n.json b/app/assets/i18n/strings_ru.i18n.json index 2b81b874a27..fa422e4cda1 100644 --- a/app/assets/i18n/strings_ru.i18n.json +++ b/app/assets/i18n/strings_ru.i18n.json @@ -218,7 +218,7 @@ "changelogPage": { "title": "История изменений" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Inherits from the English version" }, "dialogs": { diff --git a/app/assets/i18n/strings_sv.i18n.json b/app/assets/i18n/strings_sv.i18n.json index 4aca4650f82..51493a4da99 100644 --- a/app/assets/i18n/strings_sv.i18n.json +++ b/app/assets/i18n/strings_sv.i18n.json @@ -214,7 +214,7 @@ "changelogPage": { "title": "Ändringslog" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Different locales may have different words, it may not match 1:1", "adjectives": [ "Bedårande", diff --git a/app/assets/i18n/strings_th.i18n.json b/app/assets/i18n/strings_th.i18n.json index 5983d3daf3d..0f4653e3b5b 100644 --- a/app/assets/i18n/strings_th.i18n.json +++ b/app/assets/i18n/strings_th.i18n.json @@ -218,7 +218,7 @@ "changelogPage": { "title": "บันทึกการเปลี่ยนแปลง" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "สถานที่ต่างกันอาจมีคำต่างกัน อาจไม่ตรงกัน 1:1", "adjectives": [ "น่ารัก", diff --git a/app/assets/i18n/strings_tr.i18n.json b/app/assets/i18n/strings_tr.i18n.json index 10de91ff51f..e690689d62d 100644 --- a/app/assets/i18n/strings_tr.i18n.json +++ b/app/assets/i18n/strings_tr.i18n.json @@ -218,7 +218,7 @@ "changelogPage": { "title": "Değişiklik günlüğü" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Inherits from the English version" }, "dialogs": { diff --git a/app/assets/i18n/strings_uk.i18n.json b/app/assets/i18n/strings_uk.i18n.json index 7c594b08923..d198e52e4cc 100644 --- a/app/assets/i18n/strings_uk.i18n.json +++ b/app/assets/i18n/strings_uk.i18n.json @@ -218,7 +218,7 @@ "changelogPage": { "title": "Історія змін" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Inherits from the English version" }, "dialogs": { diff --git a/app/assets/i18n/strings_ur.i18n.json b/app/assets/i18n/strings_ur.i18n.json index 0ab6e289e25..2ebb650754a 100644 --- a/app/assets/i18n/strings_ur.i18n.json +++ b/app/assets/i18n/strings_ur.i18n.json @@ -214,7 +214,7 @@ "changelogPage": { "title": "چینج لاگ" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Inherits from the English version" }, "dialogs": { diff --git a/app/assets/i18n/strings_zh-CN.i18n.json b/app/assets/i18n/strings_zh-CN.i18n.json index 320eaf93f80..48899dc31a3 100644 --- a/app/assets/i18n/strings_zh-CN.i18n.json +++ b/app/assets/i18n/strings_zh-CN.i18n.json @@ -218,7 +218,7 @@ "changelogPage": { "title": "更新日志" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Inherits from the English version" }, "dialogs": { diff --git a/app/assets/i18n/strings_zh-TW.i18n.json b/app/assets/i18n/strings_zh-TW.i18n.json index 3157ef7934e..ac2f6ff2970 100644 --- a/app/assets/i18n/strings_zh-TW.i18n.json +++ b/app/assets/i18n/strings_zh-TW.i18n.json @@ -218,7 +218,7 @@ "changelogPage": { "title": "變更記錄" }, - "aliasGenerator(ignoreMissing)": { + "aliasGenerator(ignoreMissing, ignoreGpt)": { "@info": "Inherits from the English version" }, "dialogs": { diff --git a/app/lib/gen/strings.g.dart b/app/lib/gen/strings.g.dart index fef0c5f2457..f4ae03b3290 100644 --- a/app/lib/gen/strings.g.dart +++ b/app/lib/gen/strings.g.dart @@ -4,7 +4,7 @@ /// To regenerate, run: `dart run slang` /// /// Locales: 33 -/// Strings: 8864 (268 per locale) +/// Strings: 8912 (270 per locale) // coverage:ignore-file diff --git a/app/lib/gen/strings_ar.g.dart b/app/lib/gen/strings_ar.g.dart index b02f9cbd1b1..f471df25c15 100644 --- a/app/lib/gen/strings_ar.g.dart +++ b/app/lib/gen/strings_ar.g.dart @@ -64,6 +64,7 @@ class _StringsGeneralAr extends _StringsGeneralEn { @override String get copiedToClipboard => 'نسخ إلى الحافظة'; @override String get decline => 'ارفض'; @override String get done => 'انتهى'; + @override String get delete => 'حذف'; @override String get edit => 'تعديل'; @override String get error => 'خطأ'; @override String get example => 'مثال'; @@ -87,6 +88,7 @@ class _StringsGeneralAr extends _StringsGeneralEn { @override String get save => 'احفظ'; @override String get unchanged => 'دون تغيير'; @override String get unknown => 'مجهول'; + @override String get noItemInClipboard => 'لا توجد عناصر في الحافظة'; } // Path: receiveTab @@ -377,8 +379,12 @@ class _StringsDialogsAr extends _StringsDialogsEn { @override late final _StringsDialogsCannotOpenFileAr cannotOpenFile = _StringsDialogsCannotOpenFileAr._(_root); @override late final _StringsDialogsEncryptionDisabledNoticeAr encryptionDisabledNotice = _StringsDialogsEncryptionDisabledNoticeAr._(_root); @override late final _StringsDialogsErrorDialogAr errorDialog = _StringsDialogsErrorDialogAr._(_root); + @override late final _StringsDialogsFavoriteDialogAr favoriteDialog = _StringsDialogsFavoriteDialogAr._(_root); + @override late final _StringsDialogsFavoriteDeleteDialogAr favoriteDeleteDialog = _StringsDialogsFavoriteDeleteDialogAr._(_root); + @override late final _StringsDialogsFavoriteEditDialogAr favoriteEditDialog = _StringsDialogsFavoriteEditDialogAr._(_root); @override late final _StringsDialogsFileInfoAr fileInfo = _StringsDialogsFileInfoAr._(_root); @override late final _StringsDialogsFileNameInputAr fileNameInput = _StringsDialogsFileNameInputAr._(_root); + @override late final _StringsDialogsHistoryClearDialogAr historyClearDialog = _StringsDialogsHistoryClearDialogAr._(_root); @override late final _StringsDialogsLocalNetworkUnauthorizedAr localNetworkUnauthorized = _StringsDialogsLocalNetworkUnauthorizedAr._(_root); @override late final _StringsDialogsMessageInputAr messageInput = _StringsDialogsMessageInputAr._(_root); @override late final _StringsDialogsNoFilesAr noFiles = _StringsDialogsNoFilesAr._(_root); @@ -488,6 +494,7 @@ class _StringsSendTabPickerAr extends _StringsSendTabPickerEn { @override String get media => 'وسائط'; @override String get text => 'نص'; @override String get app => 'تطبيق'; + @override String get clipboard => 'لصق'; } // Path: sendTab.sendModes @@ -673,6 +680,44 @@ class _StringsDialogsErrorDialogAr extends _StringsDialogsErrorDialogEn { @override String get title => '${_root.general.error}'; } +// Path: dialogs.favoriteDialog +class _StringsDialogsFavoriteDialogAr extends _StringsDialogsFavoriteDialogEn { + _StringsDialogsFavoriteDialogAr._(_StringsAr root) : this._root = root, super._(root); + + @override final _StringsAr _root; // ignore: unused_field + + // Translations + @override String get title => 'المفضلة'; + @override String get noFavorites => 'لا توجد أجهزة مفضلة بعد.'; + @override String get addFavorite => 'إضافة'; +} + +// Path: dialogs.favoriteDeleteDialog +class _StringsDialogsFavoriteDeleteDialogAr extends _StringsDialogsFavoriteDeleteDialogEn { + _StringsDialogsFavoriteDeleteDialogAr._(_StringsAr root) : this._root = root, super._(root); + + @override final _StringsAr _root; // ignore: unused_field + + // Translations + @override String get title => 'حذف من المفضلة'; + @override String content({required Object name}) => 'هل ترغب حقًا في حذف "${name}" من قائمة المفضلة؟'; +} + +// Path: dialogs.favoriteEditDialog +class _StringsDialogsFavoriteEditDialogAr extends _StringsDialogsFavoriteEditDialogEn { + _StringsDialogsFavoriteEditDialogAr._(_StringsAr root) : this._root = root, super._(root); + + @override final _StringsAr _root; // ignore: unused_field + + // Translations + @override String get titleAdd => 'إضافة إلى المفضلة'; + @override String get titleEdit => 'تعديل'; + @override String get name => 'الاسم'; + @override String get auto => '(تلقائي)'; + @override String get ip => 'عنوان IP'; + @override String get port => 'Port'; +} + // Path: dialogs.fileInfo class _StringsDialogsFileInfoAr extends _StringsDialogsFileInfoEn { _StringsDialogsFileInfoAr._(_StringsAr root) : this._root = root, super._(root); @@ -699,6 +744,17 @@ class _StringsDialogsFileNameInputAr extends _StringsDialogsFileNameInputEn { @override String original({required Object original}) => 'أصلي: ${original}'; } +// Path: dialogs.historyClearDialog +class _StringsDialogsHistoryClearDialogAr extends _StringsDialogsHistoryClearDialogEn { + _StringsDialogsHistoryClearDialogAr._(_StringsAr root) : this._root = root, super._(root); + + @override final _StringsAr _root; // ignore: unused_field + + // Translations + @override String get title => 'محو السجل'; + @override String get content => 'هل ترغب حقًا في محو السجل بالكامل؟'; +} + // Path: dialogs.localNetworkUnauthorized class _StringsDialogsLocalNetworkUnauthorizedAr extends _StringsDialogsLocalNetworkUnauthorizedEn { _StringsDialogsLocalNetworkUnauthorizedAr._(_StringsAr root) : this._root = root, super._(root); @@ -824,6 +880,7 @@ class _StringsSettingsTabGeneralColorOptionsAr extends _StringsSettingsTabGenera // Translations @override String get system => 'النظام'; + @override String get oled => 'OLED'; } // Path: settingsTab.general.languageOptions diff --git a/app/lib/gen/strings_fa.g.dart b/app/lib/gen/strings_fa.g.dart index b84a18cf9d8..a3c2de16cf7 100644 --- a/app/lib/gen/strings_fa.g.dart +++ b/app/lib/gen/strings_fa.g.dart @@ -64,6 +64,7 @@ class _StringsGeneralFa extends _StringsGeneralEn { @override String get copiedToClipboard => 'در کلیپ بورد کپی شد'; @override String get decline => 'نپذیرفتن'; @override String get done => 'انجام شد'; + @override String get delete => 'حذف'; @override String get edit => 'ویرایش'; @override String get error => 'خطا'; @override String get example => 'مثال'; @@ -378,8 +379,12 @@ class _StringsDialogsFa extends _StringsDialogsEn { @override late final _StringsDialogsCannotOpenFileFa cannotOpenFile = _StringsDialogsCannotOpenFileFa._(_root); @override late final _StringsDialogsEncryptionDisabledNoticeFa encryptionDisabledNotice = _StringsDialogsEncryptionDisabledNoticeFa._(_root); @override late final _StringsDialogsErrorDialogFa errorDialog = _StringsDialogsErrorDialogFa._(_root); + @override late final _StringsDialogsFavoriteDialogFa favoriteDialog = _StringsDialogsFavoriteDialogFa._(_root); + @override late final _StringsDialogsFavoriteDeleteDialogFa favoriteDeleteDialog = _StringsDialogsFavoriteDeleteDialogFa._(_root); + @override late final _StringsDialogsFavoriteEditDialogFa favoriteEditDialog = _StringsDialogsFavoriteEditDialogFa._(_root); @override late final _StringsDialogsFileInfoFa fileInfo = _StringsDialogsFileInfoFa._(_root); @override late final _StringsDialogsFileNameInputFa fileNameInput = _StringsDialogsFileNameInputFa._(_root); + @override late final _StringsDialogsHistoryClearDialogFa historyClearDialog = _StringsDialogsHistoryClearDialogFa._(_root); @override late final _StringsDialogsLocalNetworkUnauthorizedFa localNetworkUnauthorized = _StringsDialogsLocalNetworkUnauthorizedFa._(_root); @override late final _StringsDialogsMessageInputFa messageInput = _StringsDialogsMessageInputFa._(_root); @override late final _StringsDialogsNoFilesFa noFiles = _StringsDialogsNoFilesFa._(_root); @@ -675,6 +680,44 @@ class _StringsDialogsErrorDialogFa extends _StringsDialogsErrorDialogEn { @override String get title => '${_root.general.error}'; } +// Path: dialogs.favoriteDialog +class _StringsDialogsFavoriteDialogFa extends _StringsDialogsFavoriteDialogEn { + _StringsDialogsFavoriteDialogFa._(_StringsFa root) : this._root = root, super._(root); + + @override final _StringsFa _root; // ignore: unused_field + + // Translations + @override String get title => 'علاقه‌مندی‌ها'; + @override String get noFavorites => 'هنوز دستگاهی اضافه نشده'; + @override String get addFavorite => 'افزودن'; +} + +// Path: dialogs.favoriteDeleteDialog +class _StringsDialogsFavoriteDeleteDialogFa extends _StringsDialogsFavoriteDeleteDialogEn { + _StringsDialogsFavoriteDeleteDialogFa._(_StringsFa root) : this._root = root, super._(root); + + @override final _StringsFa _root; // ignore: unused_field + + // Translations + @override String get title => 'حذف از علاقه‌مندی‌ها'; + @override String content({required Object name}) => 'واقعاً می خواهید از علاقه‌مندی‌ها حذف کنید "${name}"?'; +} + +// Path: dialogs.favoriteEditDialog +class _StringsDialogsFavoriteEditDialogFa extends _StringsDialogsFavoriteEditDialogEn { + _StringsDialogsFavoriteEditDialogFa._(_StringsFa root) : this._root = root, super._(root); + + @override final _StringsFa _root; // ignore: unused_field + + // Translations + @override String get titleAdd => 'افزودن به علاقه‌مندی‌ها'; + @override String get titleEdit => 'تنظیمات'; + @override String get name => 'نام مستعار'; + @override String get auto => '(خودکار)'; + @override String get ip => 'آدرس آی پی'; + @override String get port => 'پورت'; +} + // Path: dialogs.fileInfo class _StringsDialogsFileInfoFa extends _StringsDialogsFileInfoEn { _StringsDialogsFileInfoFa._(_StringsFa root) : this._root = root, super._(root); @@ -701,6 +744,17 @@ class _StringsDialogsFileNameInputFa extends _StringsDialogsFileNameInputEn { @override String original({required Object original}) => 'اصلی: ${original}'; } +// Path: dialogs.historyClearDialog +class _StringsDialogsHistoryClearDialogFa extends _StringsDialogsHistoryClearDialogEn { + _StringsDialogsHistoryClearDialogFa._(_StringsFa root) : this._root = root, super._(root); + + @override final _StringsFa _root; // ignore: unused_field + + // Translations + @override String get title => 'پاکسازی تاریخچه'; + @override String get content => 'واقعاً می خواهید کل تاریخچه را حذف کنید؟'; +} + // Path: dialogs.localNetworkUnauthorized class _StringsDialogsLocalNetworkUnauthorizedFa extends _StringsDialogsLocalNetworkUnauthorizedEn { _StringsDialogsLocalNetworkUnauthorizedFa._(_StringsFa root) : this._root = root, super._(root); diff --git a/app/lib/gen/strings_pl.g.dart b/app/lib/gen/strings_pl.g.dart index 92271144630..a3045775beb 100644 --- a/app/lib/gen/strings_pl.g.dart +++ b/app/lib/gen/strings_pl.g.dart @@ -64,6 +64,7 @@ class _StringsGeneralPl extends _StringsGeneralEn { @override String get copiedToClipboard => 'Skopiowane do Schowka'; @override String get decline => 'Odrzuć'; @override String get done => 'Gotowe'; + @override String get delete => 'Usuń'; @override String get edit => 'Edytuj'; @override String get error => 'Błąd'; @override String get example => 'Przykład'; @@ -87,6 +88,7 @@ class _StringsGeneralPl extends _StringsGeneralEn { @override String get save => 'Zapisz'; @override String get unchanged => 'Bez Zmian'; @override String get unknown => 'Nieznany'; + @override String get noItemInClipboard => 'Schowek jest pusty'; } // Path: receiveTab @@ -306,8 +308,12 @@ class _StringsDialogsPl extends _StringsDialogsEn { @override late final _StringsDialogsCannotOpenFilePl cannotOpenFile = _StringsDialogsCannotOpenFilePl._(_root); @override late final _StringsDialogsEncryptionDisabledNoticePl encryptionDisabledNotice = _StringsDialogsEncryptionDisabledNoticePl._(_root); @override late final _StringsDialogsErrorDialogPl errorDialog = _StringsDialogsErrorDialogPl._(_root); + @override late final _StringsDialogsFavoriteDialogPl favoriteDialog = _StringsDialogsFavoriteDialogPl._(_root); + @override late final _StringsDialogsFavoriteDeleteDialogPl favoriteDeleteDialog = _StringsDialogsFavoriteDeleteDialogPl._(_root); + @override late final _StringsDialogsFavoriteEditDialogPl favoriteEditDialog = _StringsDialogsFavoriteEditDialogPl._(_root); @override late final _StringsDialogsFileInfoPl fileInfo = _StringsDialogsFileInfoPl._(_root); @override late final _StringsDialogsFileNameInputPl fileNameInput = _StringsDialogsFileNameInputPl._(_root); + @override late final _StringsDialogsHistoryClearDialogPl historyClearDialog = _StringsDialogsHistoryClearDialogPl._(_root); @override late final _StringsDialogsLocalNetworkUnauthorizedPl localNetworkUnauthorized = _StringsDialogsLocalNetworkUnauthorizedPl._(_root); @override late final _StringsDialogsMessageInputPl messageInput = _StringsDialogsMessageInputPl._(_root); @override late final _StringsDialogsNoFilesPl noFiles = _StringsDialogsNoFilesPl._(_root); @@ -417,6 +423,7 @@ class _StringsSendTabPickerPl extends _StringsSendTabPickerEn { @override String get media => 'Media'; @override String get text => 'Tekst'; @override String get app => 'Aplikacja'; + @override String get clipboard => 'Wklej'; } // Path: sendTab.sendModes @@ -602,6 +609,44 @@ class _StringsDialogsErrorDialogPl extends _StringsDialogsErrorDialogEn { @override String get title => '${_root.general.error}'; } +// Path: dialogs.favoriteDialog +class _StringsDialogsFavoriteDialogPl extends _StringsDialogsFavoriteDialogEn { + _StringsDialogsFavoriteDialogPl._(_StringsPl root) : this._root = root, super._(root); + + @override final _StringsPl _root; // ignore: unused_field + + // Translations + @override String get title => 'Ulubione'; + @override String get noFavorites => 'Brak ulubionych urządzeń.'; + @override String get addFavorite => 'Dodaj'; +} + +// Path: dialogs.favoriteDeleteDialog +class _StringsDialogsFavoriteDeleteDialogPl extends _StringsDialogsFavoriteDeleteDialogEn { + _StringsDialogsFavoriteDeleteDialogPl._(_StringsPl root) : this._root = root, super._(root); + + @override final _StringsPl _root; // ignore: unused_field + + // Translations + @override String get title => 'Usuń z ulubionych'; + @override String content({required Object name}) => 'Czy na pewno chcesz usunąć z ulubionych "${name}"?'; +} + +// Path: dialogs.favoriteEditDialog +class _StringsDialogsFavoriteEditDialogPl extends _StringsDialogsFavoriteEditDialogEn { + _StringsDialogsFavoriteEditDialogPl._(_StringsPl root) : this._root = root, super._(root); + + @override final _StringsPl _root; // ignore: unused_field + + // Translations + @override String get titleAdd => 'Dodaj do ulubionych'; + @override String get titleEdit => 'Dostosuj'; + @override String get name => 'Alias'; + @override String get auto => '(auto)'; + @override String get ip => 'Adres IP'; + @override String get port => 'Port'; +} + // Path: dialogs.fileInfo class _StringsDialogsFileInfoPl extends _StringsDialogsFileInfoEn { _StringsDialogsFileInfoPl._(_StringsPl root) : this._root = root, super._(root); @@ -628,6 +673,17 @@ class _StringsDialogsFileNameInputPl extends _StringsDialogsFileNameInputEn { @override String original({required Object original}) => 'Oryginalny: ${original}'; } +// Path: dialogs.historyClearDialog +class _StringsDialogsHistoryClearDialogPl extends _StringsDialogsHistoryClearDialogEn { + _StringsDialogsHistoryClearDialogPl._(_StringsPl root) : this._root = root, super._(root); + + @override final _StringsPl _root; // ignore: unused_field + + // Translations + @override String get title => 'Wyczyść historię'; + @override String get content => 'Czy na pewno chcesz usunąć całą historię?'; +} + // Path: dialogs.localNetworkUnauthorized class _StringsDialogsLocalNetworkUnauthorizedPl extends _StringsDialogsLocalNetworkUnauthorizedEn { _StringsDialogsLocalNetworkUnauthorizedPl._(_StringsPl root) : this._root = root, super._(root); @@ -753,6 +809,7 @@ class _StringsSettingsTabGeneralColorOptionsPl extends _StringsSettingsTabGenera // Translations @override String get system => 'System'; + @override String get oled => 'OLED'; } // Path: settingsTab.general.languageOptions From 430e9aac1db3638f0f764f77868c3e828f8610ab Mon Sep 17 00:00:00 2001 From: Tien Do Nam Date: Fri, 17 Nov 2023 23:54:32 +0100 Subject: [PATCH 19/31] deps: bump refena --- app/pubspec.lock | 16 ++++++++-------- app/pubspec.yaml | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/pubspec.lock b/app/pubspec.lock index 9d3ccd701fd..e417ca422c8 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -1089,34 +1089,34 @@ packages: dependency: transitive description: name: refena - sha256: "2d810cc535a081fa4d2183fd9e172821db5ae19d65bed2d7fd543670b2c5cab3" + sha256: a5a94117091cc032418b6cc5bd7891fdec838262aa3f009bb9b8488a4297d077 url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.2.0" refena_flutter: dependency: "direct main" description: name: refena_flutter - sha256: "236b150a1e0098a1bbe521299121df55fea6962cf6e034181c4f2e21c1a91f54" + sha256: "23a359c27d98fad16e2b3d7ddbc7c5fd8df64e81f0012471ee0ac0170f11e09d" url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.2.0" refena_inspector: dependency: "direct dev" description: name: refena_inspector - sha256: "03b41ce4ebb1b6f15d6e975d062fa97f045ece8ebdbb7979ee8b6716cdb5080e" + sha256: "799d1a582be72d69b89e426bf96949c67b40cea92015aa0ab568d4d0608e89e6" url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.1.0" refena_inspector_client: dependency: "direct main" description: name: refena_inspector_client - sha256: "4fbbd54c04ac5382e20081ad0d625abfcfddb395a0dabb3e331de62419cd6ef5" + sha256: "474dd169eb3cc11d1fbffe7f0672138a34d99cb590ab52224acb317f7499a4cb" url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.1.0" routerino: dependency: "direct main" description: diff --git a/app/pubspec.yaml b/app/pubspec.yaml index f55d06690ba..b4db64efdf7 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -43,8 +43,8 @@ dependencies: path_provider: 2.1.1 permission_handler: 11.0.1 pretty_qr_code: 2.0.3 - refena_flutter: 1.0.0 - refena_inspector_client: 1.0.0 + refena_flutter: 1.2.0 + refena_inspector_client: 1.1.0 routerino: 0.8.0 screen_retriever: 0.1.9 share_handler: 0.0.19 @@ -74,7 +74,7 @@ dev_dependencies: flutter_gen_runner: 5.3.2 flutter_lints: 2.0.3 msix: 3.16.4 - refena_inspector: 1.0.0 + refena_inspector: 1.1.0 slang_build_runner: 3.25.0 slang_gpt: 0.10.0 test: ^1.24.3 From fe05921250da53b0caec9efe4365ed2646157c18 Mon Sep 17 00:00:00 2001 From: Tien Do Nam Date: Fri, 17 Nov 2023 23:57:20 +0100 Subject: [PATCH 20/31] fix: duplicate watch --- app/lib/pages/tabs/send_tab_vm.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/pages/tabs/send_tab_vm.dart b/app/lib/pages/tabs/send_tab_vm.dart index 013e089a58c..174a37f8ac2 100644 --- a/app/lib/pages/tabs/send_tab_vm.dart +++ b/app/lib/pages/tabs/send_tab_vm.dart @@ -63,7 +63,7 @@ final sendTabVmProvider = ViewProvider((ref) { selectedFiles: selectedFiles, localIps: localIps, nearbyDevices: nearbyDevices, - favoriteDevices: ref.watch(favoritesProvider), + favoriteDevices: favoriteDevices, onTapAddress: (context) async { final files = ref.read(selectedSendingFilesProvider); if (files.isEmpty) { From a08b88da949d8ebcef1162b8cde2cefc9dd3585a Mon Sep 17 00:00:00 2001 From: Tien Do Nam <38380847+Tienisto@users.noreply.github.com> Date: Sat, 18 Nov 2023 17:20:25 +0100 Subject: [PATCH 21/31] feat: add donation options (#910) --- app/assets/CHANGELOG.md | 1 + app/assets/i18n/_missing_translations_ar.json | 19 +- app/assets/i18n/_missing_translations_bn.json | 19 +- app/assets/i18n/_missing_translations_ca.json | 15 ++ app/assets/i18n/_missing_translations_cs.json | 19 +- app/assets/i18n/_missing_translations_el.json | 19 +- .../i18n/_missing_translations_es_ES.json | 19 +- app/assets/i18n/_missing_translations_eu.json | 17 ++ app/assets/i18n/_missing_translations_fa.json | 19 +- .../i18n/_missing_translations_fil_PH.json | 19 +- .../i18n/_missing_translations_fr_FR.json | 19 +- app/assets/i18n/_missing_translations_he.json | 19 +- app/assets/i18n/_missing_translations_hu.json | 19 +- app/assets/i18n/_missing_translations_id.json | 15 ++ app/assets/i18n/_missing_translations_it.json | 19 +- app/assets/i18n/_missing_translations_ja.json | 19 +- app/assets/i18n/_missing_translations_km.json | 17 ++ app/assets/i18n/_missing_translations_ko.json | 19 +- app/assets/i18n/_missing_translations_ne.json | 15 ++ app/assets/i18n/_missing_translations_nl.json | 19 +- app/assets/i18n/_missing_translations_pl.json | 19 +- .../i18n/_missing_translations_pt_BR.json | 17 ++ app/assets/i18n/_missing_translations_ru.json | 19 +- app/assets/i18n/_missing_translations_sv.json | 15 ++ app/assets/i18n/_missing_translations_th.json | 19 +- app/assets/i18n/_missing_translations_tr.json | 17 ++ app/assets/i18n/_missing_translations_uk.json | 19 +- app/assets/i18n/_missing_translations_ur.json | 15 ++ app/assets/i18n/_missing_translations_vi.json | 19 +- .../i18n/_missing_translations_zh_CN.json | 19 +- .../i18n/_missing_translations_zh_HK.json | 19 +- .../i18n/_missing_translations_zh_TW.json | 19 +- app/assets/i18n/strings.i18n.json | 15 ++ app/assets/i18n/strings_de.i18n.json | 15 ++ app/ios/MyLocalSendStoreKit.storekit | 130 ++++++++++++ app/ios/Podfile.lock | 7 + app/ios/Runner.xcodeproj/project.pbxproj | 4 + .../xcshareddata/xcschemes/Runner.xcscheme | 3 + app/lib/gen/strings.g.dart | 2 +- app/lib/gen/strings_de.g.dart | 31 +++ app/lib/gen/strings_en.g.dart | 31 +++ app/lib/init.dart | 7 + app/lib/model/state/purchase_state.dart | 47 +++++ .../model/state/purchase_state.mapper.dart | 150 ++++++++++++++ app/lib/pages/donation/donation_page.dart | 110 +++++++++++ app/lib/pages/donation/donation_page_vm.dart | 30 +++ app/lib/pages/tabs/settings_tab.dart | 135 ++++++++----- app/lib/provider/purchase_provider.dart | 187 ++++++++++++++++++ app/lib/util/native/platform_check.dart | 5 + .../Flutter/GeneratedPluginRegistrant.swift | 2 + app/macos/Podfile.lock | 7 + .../xcshareddata/xcschemes/Runner.xcscheme | 3 + .../contents.xcworkspacedata | 3 + app/pubspec.lock | 32 +++ app/pubspec.yaml | 1 + 55 files changed, 1452 insertions(+), 67 deletions(-) create mode 100644 app/ios/MyLocalSendStoreKit.storekit create mode 100644 app/lib/model/state/purchase_state.dart create mode 100644 app/lib/model/state/purchase_state.mapper.dart create mode 100644 app/lib/pages/donation/donation_page.dart create mode 100644 app/lib/pages/donation/donation_page_vm.dart create mode 100644 app/lib/provider/purchase_provider.dart diff --git a/app/assets/CHANGELOG.md b/app/assets/CHANGELOG.md index 7b60cf66867..9e433fe5fe0 100644 --- a/app/assets/CHANGELOG.md +++ b/app/assets/CHANGELOG.md @@ -1,6 +1,7 @@ ## 1.13.0 (unreleased) - feat: ignore duplicate files when selected from file picker (@programmermager) +- feat: add donation options (@Tienisto) - i18n: add Greek (@multipetros) ## 1.12.0 (2023-10-25) diff --git a/app/assets/i18n/_missing_translations_ar.json b/app/assets/i18n/_missing_translations_ar.json index 69291e3d5d6..163785c47ec 100644 --- a/app/assets/i18n/_missing_translations_ar.json +++ b/app/assets/i18n/_missing_translations_ar.json @@ -2,5 +2,22 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=ar' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + } } diff --git a/app/assets/i18n/_missing_translations_bn.json b/app/assets/i18n/_missing_translations_bn.json index 3df1d5486eb..645fa477de0 100644 --- a/app/assets/i18n/_missing_translations_bn.json +++ b/app/assets/i18n/_missing_translations_bn.json @@ -2,5 +2,22 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=bn' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + } } diff --git a/app/assets/i18n/_missing_translations_ca.json b/app/assets/i18n/_missing_translations_ca.json index 0f6208739a5..3aa994d8302 100644 --- a/app/assets/i18n/_missing_translations_ca.json +++ b/app/assets/i18n/_missing_translations_ca.json @@ -17,8 +17,23 @@ "colorOptions": { "oled": "OLED" } + }, + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" } }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + }, "dialogs": { "favoriteDialog": { "title": "Favorites", diff --git a/app/assets/i18n/_missing_translations_cs.json b/app/assets/i18n/_missing_translations_cs.json index 4baf9cddb63..0219bd47453 100644 --- a/app/assets/i18n/_missing_translations_cs.json +++ b/app/assets/i18n/_missing_translations_cs.json @@ -2,5 +2,22 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=cs' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + } } diff --git a/app/assets/i18n/_missing_translations_el.json b/app/assets/i18n/_missing_translations_el.json index dcd86656802..d2f2657290c 100644 --- a/app/assets/i18n/_missing_translations_el.json +++ b/app/assets/i18n/_missing_translations_el.json @@ -2,5 +2,22 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=el' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + } } diff --git a/app/assets/i18n/_missing_translations_es_ES.json b/app/assets/i18n/_missing_translations_es_ES.json index b72625b90b5..72c0c0a8adb 100644 --- a/app/assets/i18n/_missing_translations_es_ES.json +++ b/app/assets/i18n/_missing_translations_es_ES.json @@ -2,5 +2,22 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=es-ES' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + } } diff --git a/app/assets/i18n/_missing_translations_eu.json b/app/assets/i18n/_missing_translations_eu.json index 332335ecd85..99ba663a38c 100644 --- a/app/assets/i18n/_missing_translations_eu.json +++ b/app/assets/i18n/_missing_translations_eu.json @@ -3,6 +3,23 @@ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=eu' to quickly apply the newly added translations." ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + }, "dialogs": { "historyClearDialog": { "title": "Clear history", diff --git a/app/assets/i18n/_missing_translations_fa.json b/app/assets/i18n/_missing_translations_fa.json index 68c22596fe7..8789913cb36 100644 --- a/app/assets/i18n/_missing_translations_fa.json +++ b/app/assets/i18n/_missing_translations_fa.json @@ -2,5 +2,22 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=fa' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + } } diff --git a/app/assets/i18n/_missing_translations_fil_PH.json b/app/assets/i18n/_missing_translations_fil_PH.json index b1fc33ef83b..e6174e5fe3a 100644 --- a/app/assets/i18n/_missing_translations_fil_PH.json +++ b/app/assets/i18n/_missing_translations_fil_PH.json @@ -2,5 +2,22 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=fil-PH' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + } } diff --git a/app/assets/i18n/_missing_translations_fr_FR.json b/app/assets/i18n/_missing_translations_fr_FR.json index e631b362a9e..8f849314554 100644 --- a/app/assets/i18n/_missing_translations_fr_FR.json +++ b/app/assets/i18n/_missing_translations_fr_FR.json @@ -2,5 +2,22 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=fr-FR' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + } } diff --git a/app/assets/i18n/_missing_translations_he.json b/app/assets/i18n/_missing_translations_he.json index acb0d4eefb4..edb887a539e 100644 --- a/app/assets/i18n/_missing_translations_he.json +++ b/app/assets/i18n/_missing_translations_he.json @@ -2,5 +2,22 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=he' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + } } diff --git a/app/assets/i18n/_missing_translations_hu.json b/app/assets/i18n/_missing_translations_hu.json index 1cb8814a2f6..60185510017 100644 --- a/app/assets/i18n/_missing_translations_hu.json +++ b/app/assets/i18n/_missing_translations_hu.json @@ -2,5 +2,22 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=hu' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + } } diff --git a/app/assets/i18n/_missing_translations_id.json b/app/assets/i18n/_missing_translations_id.json index 5117770ff8c..aff018b97ee 100644 --- a/app/assets/i18n/_missing_translations_id.json +++ b/app/assets/i18n/_missing_translations_id.json @@ -17,8 +17,23 @@ "colorOptions": { "oled": "OLED" } + }, + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" } }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + }, "dialogs": { "favoriteDialog": { "title": "Favorites", diff --git a/app/assets/i18n/_missing_translations_it.json b/app/assets/i18n/_missing_translations_it.json index ba21f191518..0702cd1d30b 100644 --- a/app/assets/i18n/_missing_translations_it.json +++ b/app/assets/i18n/_missing_translations_it.json @@ -2,5 +2,22 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=it' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + } } diff --git a/app/assets/i18n/_missing_translations_ja.json b/app/assets/i18n/_missing_translations_ja.json index 907db9a4feb..a9d88d1d609 100644 --- a/app/assets/i18n/_missing_translations_ja.json +++ b/app/assets/i18n/_missing_translations_ja.json @@ -2,5 +2,22 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=ja' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + } } diff --git a/app/assets/i18n/_missing_translations_km.json b/app/assets/i18n/_missing_translations_km.json index e0980f2b4e2..a6bb8d9c398 100644 --- a/app/assets/i18n/_missing_translations_km.json +++ b/app/assets/i18n/_missing_translations_km.json @@ -12,6 +12,23 @@ "clipboard": "Paste" } }, + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + }, "dialogs": { "favoriteDialog": { "title": "Favorites", diff --git a/app/assets/i18n/_missing_translations_ko.json b/app/assets/i18n/_missing_translations_ko.json index 5d6de78354d..29776cf45ff 100644 --- a/app/assets/i18n/_missing_translations_ko.json +++ b/app/assets/i18n/_missing_translations_ko.json @@ -2,5 +2,22 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=ko' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + } } diff --git a/app/assets/i18n/_missing_translations_ne.json b/app/assets/i18n/_missing_translations_ne.json index 3fec622366e..e030c8c2a59 100644 --- a/app/assets/i18n/_missing_translations_ne.json +++ b/app/assets/i18n/_missing_translations_ne.json @@ -17,8 +17,23 @@ "colorOptions": { "oled": "OLED" } + }, + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" } }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + }, "dialogs": { "favoriteDialog": { "title": "Favorites", diff --git a/app/assets/i18n/_missing_translations_nl.json b/app/assets/i18n/_missing_translations_nl.json index 92901284587..8be292e789b 100644 --- a/app/assets/i18n/_missing_translations_nl.json +++ b/app/assets/i18n/_missing_translations_nl.json @@ -2,5 +2,22 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=nl' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + } } diff --git a/app/assets/i18n/_missing_translations_pl.json b/app/assets/i18n/_missing_translations_pl.json index 0da0da9af82..b79825868ac 100644 --- a/app/assets/i18n/_missing_translations_pl.json +++ b/app/assets/i18n/_missing_translations_pl.json @@ -2,5 +2,22 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=pl' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + } } diff --git a/app/assets/i18n/_missing_translations_pt_BR.json b/app/assets/i18n/_missing_translations_pt_BR.json index a65b7c1e377..e09a8fcbc4a 100644 --- a/app/assets/i18n/_missing_translations_pt_BR.json +++ b/app/assets/i18n/_missing_translations_pt_BR.json @@ -3,6 +3,23 @@ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=pt-BR' to quickly apply the newly added translations." ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + }, "dialogs": { "historyClearDialog": { "title": "Clear history", diff --git a/app/assets/i18n/_missing_translations_ru.json b/app/assets/i18n/_missing_translations_ru.json index d69f5f8cfb6..6f53b5bc463 100644 --- a/app/assets/i18n/_missing_translations_ru.json +++ b/app/assets/i18n/_missing_translations_ru.json @@ -2,5 +2,22 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=ru' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + } } diff --git a/app/assets/i18n/_missing_translations_sv.json b/app/assets/i18n/_missing_translations_sv.json index 9b3cc3147a3..6d3f9a58d20 100644 --- a/app/assets/i18n/_missing_translations_sv.json +++ b/app/assets/i18n/_missing_translations_sv.json @@ -17,8 +17,23 @@ "colorOptions": { "oled": "OLED" } + }, + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" } }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + }, "dialogs": { "favoriteDialog": { "title": "Favorites", diff --git a/app/assets/i18n/_missing_translations_th.json b/app/assets/i18n/_missing_translations_th.json index ab20ca6f415..5f63ac868be 100644 --- a/app/assets/i18n/_missing_translations_th.json +++ b/app/assets/i18n/_missing_translations_th.json @@ -2,5 +2,22 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=th' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + } } diff --git a/app/assets/i18n/_missing_translations_tr.json b/app/assets/i18n/_missing_translations_tr.json index 98fbaeb1168..5bb50bcb31d 100644 --- a/app/assets/i18n/_missing_translations_tr.json +++ b/app/assets/i18n/_missing_translations_tr.json @@ -3,6 +3,23 @@ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=tr' to quickly apply the newly added translations." ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + }, "dialogs": { "historyClearDialog": { "title": "Clear history", diff --git a/app/assets/i18n/_missing_translations_uk.json b/app/assets/i18n/_missing_translations_uk.json index 4eb0fee15b7..e2fb4a198b5 100644 --- a/app/assets/i18n/_missing_translations_uk.json +++ b/app/assets/i18n/_missing_translations_uk.json @@ -2,5 +2,22 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=uk' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + } } diff --git a/app/assets/i18n/_missing_translations_ur.json b/app/assets/i18n/_missing_translations_ur.json index e46c296f01b..559970455ae 100644 --- a/app/assets/i18n/_missing_translations_ur.json +++ b/app/assets/i18n/_missing_translations_ur.json @@ -17,8 +17,23 @@ "colorOptions": { "oled": "OLED" } + }, + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" } }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + }, "dialogs": { "favoriteDialog": { "title": "Favorites", diff --git a/app/assets/i18n/_missing_translations_vi.json b/app/assets/i18n/_missing_translations_vi.json index 23aabe21a78..118698ef630 100644 --- a/app/assets/i18n/_missing_translations_vi.json +++ b/app/assets/i18n/_missing_translations_vi.json @@ -2,5 +2,22 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=vi' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + } } diff --git a/app/assets/i18n/_missing_translations_zh_CN.json b/app/assets/i18n/_missing_translations_zh_CN.json index babbeb2bbe5..a30d5ceb6b4 100644 --- a/app/assets/i18n/_missing_translations_zh_CN.json +++ b/app/assets/i18n/_missing_translations_zh_CN.json @@ -2,5 +2,22 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=zh-CN' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + } } diff --git a/app/assets/i18n/_missing_translations_zh_HK.json b/app/assets/i18n/_missing_translations_zh_HK.json index 00c8a7ffe92..fc6fcdbb1f0 100644 --- a/app/assets/i18n/_missing_translations_zh_HK.json +++ b/app/assets/i18n/_missing_translations_zh_HK.json @@ -2,5 +2,22 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=zh-HK' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + } } diff --git a/app/assets/i18n/_missing_translations_zh_TW.json b/app/assets/i18n/_missing_translations_zh_TW.json index 2989e35b871..05e1acd35f5 100644 --- a/app/assets/i18n/_missing_translations_zh_TW.json +++ b/app/assets/i18n/_missing_translations_zh_TW.json @@ -2,5 +2,22 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=zh-TW' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + } + }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + } } diff --git a/app/assets/i18n/strings.i18n.json b/app/assets/i18n/strings.i18n.json index ca004e4ca01..d5295599554 100644 --- a/app/assets/i18n/strings.i18n.json +++ b/app/assets/i18n/strings.i18n.json @@ -123,6 +123,14 @@ "multicastGroup": "Multicast", "multicastGroupWarning": "You might not be detected by other devices because you are using a custom multicast address. (default: {defaultMulticast})" }, + "other": { + "title": "Other", + "about": "About", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" + }, "advancedSettings": "Advanced settings" }, "troubleshootPage": { @@ -215,6 +223,13 @@ "aboutPage": { "title": "About LocalSend" }, + "donationPage": { + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" + }, "changelogPage": { "title": "Changelog" }, diff --git a/app/assets/i18n/strings_de.i18n.json b/app/assets/i18n/strings_de.i18n.json index e4ff586f4b4..d5ff2249437 100644 --- a/app/assets/i18n/strings_de.i18n.json +++ b/app/assets/i18n/strings_de.i18n.json @@ -123,6 +123,14 @@ "multicastGroup": "Multicast", "multicastGroupWarning": "Möglicherweise wirst du von anderen Geräten nicht erkannt, weil du eine benutzerdefinierte Multicast-Adresse verwendest. (Standard: {defaultMulticast})" }, + "other": { + "title": "Weitere", + "about": "Über", + "support": "LocalSend unterstützen", + "donate": "Spenden", + "privacyPolicy": "Datenschutzerklärung", + "termsOfUse": "Nutzungsbedingungen" + }, "advancedSettings": "Erweiterte Einstellungen" }, "troubleshootPage": { @@ -215,6 +223,13 @@ "aboutPage": { "title": "Über LocalSend" }, + "donationPage": { + "title": "Spenden", + "info": "LocalSend ist kostenlos, open-source und frei von Werbung. Wenn dir diese App gefällt, kannst du die Entwicklung mit einer Spende unterstützen.", + "donate": "Spende {amount}", + "thanks": "Vielen Dank für deine Unterstützung!", + "restore": "Käufe Wiederherstellen" + }, "changelogPage": { "title": "Changelog" }, diff --git a/app/ios/MyLocalSendStoreKit.storekit b/app/ios/MyLocalSendStoreKit.storekit new file mode 100644 index 00000000000..ea71637c6ec --- /dev/null +++ b/app/ios/MyLocalSendStoreKit.storekit @@ -0,0 +1,130 @@ +{ + "identifier" : "D8FDEAE9", + "nonRenewingSubscriptions" : [ + + ], + "products" : [ + { + "displayPrice" : "4.0", + "familyShareable" : false, + "internalID" : "6472594578", + "localizations" : [ + { + "description" : "LocalSend Donation", + "displayName" : "LocalSend Donation", + "locale" : "en_US" + } + ], + "productID" : "localsend_ios_donate_5", + "referenceName" : "LocalSend Donation (05)", + "type" : "NonConsumable" + }, + { + "displayPrice" : "9.0", + "familyShareable" : false, + "internalID" : "6472594779", + "localizations" : [ + { + "description" : "LocalSend Donation", + "displayName" : "LocalSend Donation", + "locale" : "en_US" + } + ], + "productID" : "localsend_ios_donate_10", + "referenceName" : "LocalSend Donation (10)", + "type" : "NonConsumable" + }, + { + "displayPrice" : "18.0", + "familyShareable" : false, + "internalID" : "6472594819", + "localizations" : [ + { + "description" : "LocalSend Donation", + "displayName" : "LocalSend Donation", + "locale" : "en_US" + } + ], + "productID" : "localsend_ios_donate_20", + "referenceName" : "LocalSend Donation (20)", + "type" : "NonConsumable" + }, + { + "displayPrice" : "45.0", + "familyShareable" : false, + "internalID" : "6472595571", + "localizations" : [ + { + "description" : "LocalSend Donation", + "displayName" : "LocalSend Donation", + "locale" : "en_US" + } + ], + "productID" : "localsend_ios_donate_50", + "referenceName" : "LocalSend Donation (50)", + "type" : "NonConsumable" + } + ], + "settings" : { + "_applicationInternalID" : "1661733229", + "_developerTeamID" : "3W7H4PYMCV", + "_failTransactionsEnabled" : false, + "_lastSynchronizedDate" : 722014387.19710302, + "_locale" : "en_US", + "_storefront" : "USA", + "_storeKitErrors" : [ + { + "current" : null, + "enabled" : false, + "name" : "Load Products" + }, + { + "current" : null, + "enabled" : false, + "name" : "Purchase" + }, + { + "current" : null, + "enabled" : false, + "name" : "Verification" + }, + { + "current" : null, + "enabled" : false, + "name" : "App Store Sync" + }, + { + "current" : null, + "enabled" : false, + "name" : "Subscription Status" + }, + { + "current" : null, + "enabled" : false, + "name" : "App Transaction" + }, + { + "current" : null, + "enabled" : false, + "name" : "Manage Subscriptions Sheet" + }, + { + "current" : null, + "enabled" : false, + "name" : "Refund Request Sheet" + }, + { + "current" : null, + "enabled" : false, + "name" : "Offer Code Redeem Sheet" + } + ] + }, + "subscriptionGroups" : [ + + ], + "version" : { + "major" : 3, + "minor" : 0 + } +} diff --git a/app/ios/Podfile.lock b/app/ios/Podfile.lock index c8f09f0d289..3e0d98a5165 100644 --- a/app/ios/Podfile.lock +++ b/app/ios/Podfile.lock @@ -46,6 +46,9 @@ PODS: - FlutterMacOS - image_picker_ios (0.0.1): - Flutter + - in_app_purchase_storekit (0.0.1): + - Flutter + - FlutterMacOS - network_info_plus (0.0.1): - Flutter - open_filex (0.0.2): @@ -96,6 +99,7 @@ DEPENDENCIES: - Flutter (from `Flutter`) - gal (from `.symlinks/plugins/gal/darwin`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) + - in_app_purchase_storekit (from `.symlinks/plugins/in_app_purchase_storekit/darwin`) - network_info_plus (from `.symlinks/plugins/network_info_plus/ios`) - open_filex (from `.symlinks/plugins/open_filex/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) @@ -134,6 +138,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/gal/darwin" image_picker_ios: :path: ".symlinks/plugins/image_picker_ios/ios" + in_app_purchase_storekit: + :path: ".symlinks/plugins/in_app_purchase_storekit/darwin" network_info_plus: :path: ".symlinks/plugins/network_info_plus/ios" open_filex: @@ -173,6 +179,7 @@ SPEC CHECKSUMS: Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 gal: 61e868295d28fe67ffa297fae6dacebf56fd53e1 image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5 + in_app_purchase_storekit: 4fb7ee9e824b1f09107fbfbbce8c4b276366dc43 network_info_plus: 6d0c3eb8367b8164fa3fb0c19875e3f59d49697f open_filex: 6e26e659846ec990262224a12ef1c528bb4edbe4 package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85 diff --git a/app/ios/Runner.xcodeproj/project.pbxproj b/app/ios/Runner.xcodeproj/project.pbxproj index ecb1355531e..5ed02d42fe3 100644 --- a/app/ios/Runner.xcodeproj/project.pbxproj +++ b/app/ios/Runner.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 7DA3203436DA0EAD484C6129 /* Pods_ShareExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 052009B9C8E63670A6F30787 /* Pods_ShareExtension.framework */; }; + 840EA3FC2B0910B000C0FED7 /* MyLocalSendStoreKit.storekit in Resources */ = {isa = PBXBuildFile; fileRef = 840EA3FB2B0910B000C0FED7 /* MyLocalSendStoreKit.storekit */; }; 841A12B929EC22BD00B99343 /* LocalNetworkAuthorization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841A12B829EC22BD00B99343 /* LocalNetworkAuthorization.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; @@ -73,6 +74,7 @@ 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 840EA3FB2B0910B000C0FED7 /* MyLocalSendStoreKit.storekit */ = {isa = PBXFileReference; lastKnownFileType = text; path = MyLocalSendStoreKit.storekit; sourceTree = ""; }; 841A12B829EC22BD00B99343 /* LocalNetworkAuthorization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalNetworkAuthorization.swift; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; @@ -144,6 +146,7 @@ 97C146E51CF9000F007C117D = { isa = PBXGroup; children = ( + 840EA3FB2B0910B000C0FED7 /* MyLocalSendStoreKit.storekit */, 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 28D9F9A329638D5E0028B96E /* ShareExtension */, @@ -288,6 +291,7 @@ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + 840EA3FC2B0910B000C0FED7 /* MyLocalSendStoreKit.storekit in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a6b826db27d..d029eb5c083 100644 --- a/app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -59,6 +59,9 @@ ReferencedContainer = "container:Runner.xcodeproj"> + + 'Erweiterte Einstellungen'; } @@ -276,6 +278,20 @@ class _StringsAboutPageDe extends _StringsAboutPageEn { @override String get title => 'Über LocalSend'; } +// Path: donationPage +class _StringsDonationPageDe extends _StringsDonationPageEn { + _StringsDonationPageDe._(_StringsDe root) : this._root = root, super._(root); + + @override final _StringsDe _root; // ignore: unused_field + + // Translations + @override String get title => 'Spenden'; + @override String get info => 'LocalSend ist kostenlos, open-source und frei von Werbung. Wenn dir diese App gefällt, kannst du die Entwicklung mit einer Spende unterstützen.'; + @override String donate({required Object amount}) => 'Spende ${amount}'; + @override String get thanks => 'Vielen Dank für deine Unterstützung!'; + @override String get restore => 'Käufe Wiederherstellen'; +} + // Path: changelogPage class _StringsChangelogPageDe extends _StringsChangelogPageEn { _StringsChangelogPageDe._(_StringsDe root) : this._root = root, super._(root); @@ -494,6 +510,21 @@ class _StringsSettingsTabNetworkDe extends _StringsSettingsTabNetworkEn { @override String multicastGroupWarning({required Object defaultMulticast}) => 'Möglicherweise wirst du von anderen Geräten nicht erkannt, weil du eine benutzerdefinierte Multicast-Adresse verwendest. (Standard: ${defaultMulticast})'; } +// Path: settingsTab.other +class _StringsSettingsTabOtherDe extends _StringsSettingsTabOtherEn { + _StringsSettingsTabOtherDe._(_StringsDe root) : this._root = root, super._(root); + + @override final _StringsDe _root; // ignore: unused_field + + // Translations + @override String get title => 'Weitere'; + @override String get about => 'Über'; + @override String get support => 'LocalSend unterstützen'; + @override String get donate => 'Spenden'; + @override String get privacyPolicy => 'Datenschutzerklärung'; + @override String get termsOfUse => 'Nutzungsbedingungen'; +} + // Path: troubleshootPage.firewall class _StringsTroubleshootPageFirewallDe extends _StringsTroubleshootPageFirewallEn { _StringsTroubleshootPageFirewallDe._(_StringsDe root) : this._root = root, super._(root); diff --git a/app/lib/gen/strings_en.g.dart b/app/lib/gen/strings_en.g.dart index 2ed479e9f7b..02ded6f7380 100644 --- a/app/lib/gen/strings_en.g.dart +++ b/app/lib/gen/strings_en.g.dart @@ -36,6 +36,7 @@ class _StringsEn implements BaseTranslations { late final _StringsProgressPageEn progressPage = _StringsProgressPageEn._(_root); late final _StringsWebSharePageEn webSharePage = _StringsWebSharePageEn._(_root); late final _StringsAboutPageEn aboutPage = _StringsAboutPageEn._(_root); + late final _StringsDonationPageEn donationPage = _StringsDonationPageEn._(_root); late final _StringsChangelogPageEn changelogPage = _StringsChangelogPageEn._(_root); late final _StringsAliasGeneratorEn aliasGenerator = _StringsAliasGeneratorEn._(_root); late final _StringsDialogsEn dialogs = _StringsDialogsEn._(_root); @@ -133,6 +134,7 @@ class _StringsSettingsTabEn { late final _StringsSettingsTabGeneralEn general = _StringsSettingsTabGeneralEn._(_root); late final _StringsSettingsTabReceiveEn receive = _StringsSettingsTabReceiveEn._(_root); late final _StringsSettingsTabNetworkEn network = _StringsSettingsTabNetworkEn._(_root); + late final _StringsSettingsTabOtherEn other = _StringsSettingsTabOtherEn._(_root); String get advancedSettings => 'Advanced settings'; } @@ -275,6 +277,20 @@ class _StringsAboutPageEn { String get title => 'About LocalSend'; } +// Path: donationPage +class _StringsDonationPageEn { + _StringsDonationPageEn._(this._root); + + final _StringsEn _root; // ignore: unused_field + + // Translations + String get title => 'Donate'; + String get info => 'LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.'; + String donate({required Object amount}) => 'Donate ${amount}'; + String get thanks => 'Thank you very much!'; + String get restore => 'Restore purchase'; +} + // Path: changelogPage class _StringsChangelogPageEn { _StringsChangelogPageEn._(this._root); @@ -564,6 +580,21 @@ class _StringsSettingsTabNetworkEn { String multicastGroupWarning({required Object defaultMulticast}) => 'You might not be detected by other devices because you are using a custom multicast address. (default: ${defaultMulticast})'; } +// Path: settingsTab.other +class _StringsSettingsTabOtherEn { + _StringsSettingsTabOtherEn._(this._root); + + final _StringsEn _root; // ignore: unused_field + + // Translations + String get title => 'Other'; + String get about => 'About'; + String get support => 'Support LocalSend'; + String get donate => 'Donate'; + String get privacyPolicy => 'Privacy Policy'; + String get termsOfUse => 'Terms of Use'; +} + // Path: troubleshootPage.firewall class _StringsTroubleshootPageFirewallEn { _StringsTroubleshootPageFirewallEn._(this._root); diff --git a/app/lib/init.dart b/app/lib/init.dart index 555dd6158be..b37998e2767 100644 --- a/app/lib/init.dart +++ b/app/lib/init.dart @@ -15,6 +15,7 @@ import 'package:localsend_app/provider/dio_provider.dart'; import 'package:localsend_app/provider/network/nearby_devices_provider.dart'; import 'package:localsend_app/provider/network/server/server_provider.dart'; import 'package:localsend_app/provider/persistence_provider.dart'; +import 'package:localsend_app/provider/purchase_provider.dart'; import 'package:localsend_app/provider/selection/selected_sending_files_provider.dart'; import 'package:localsend_app/provider/tv_provider.dart'; import 'package:localsend_app/provider/window_dimensions_provider.dart'; @@ -171,6 +172,12 @@ Future postInit(BuildContext context, Ref ref, bool appStart, void Functio // If we received a share intent, then don't clear it, otherwise the shared file will be lost. ref.dispatch(ClearCacheAction()); } + + + if (checkPlatformSupportPayment()) { + // ignore: unawaited_futures + ref.redux(purchaseProvider).dispatchAsync(InitPurchaseStream()); + } } class _HandleShareIntentAction extends AsyncGlobalAction { diff --git a/app/lib/model/state/purchase_state.dart b/app/lib/model/state/purchase_state.dart new file mode 100644 index 00000000000..37ae57234c5 --- /dev/null +++ b/app/lib/model/state/purchase_state.dart @@ -0,0 +1,47 @@ +import 'package:dart_mappable/dart_mappable.dart'; +import 'package:flutter/foundation.dart'; +import 'package:in_app_purchase/in_app_purchase.dart'; + +part 'purchase_state.mapper.dart'; + +enum PurchaseItem { + donate5( + androidId: 'localsend_android_donate_5', + iosId: 'localsend_ios_donate_5', + ), + donate10( + androidId: 'localsend_android_donate_10', + iosId: 'localsend_ios_donate_10', + ), + donate20( + androidId: 'localsend_android_donate_20', + iosId: 'localsend_ios_donate_20', + ), + donate50( + androidId: 'localsend_android_donate_50', + iosId: 'localsend_ios_donate_50', + ); + + const PurchaseItem({ + required this.androidId, + required this.iosId, + }); + + final String androidId; + final String iosId; + + String get platformProductId => defaultTargetPlatform == TargetPlatform.android ? androidId : iosId; +} + +@MappableClass() +class PurchaseState with PurchaseStateMappable { + final Map prices; + final Map purchases; + final bool pending; + + const PurchaseState({ + required this.prices, + required this.purchases, + required this.pending, + }); +} diff --git a/app/lib/model/state/purchase_state.mapper.dart b/app/lib/model/state/purchase_state.mapper.dart new file mode 100644 index 00000000000..75b462807d5 --- /dev/null +++ b/app/lib/model/state/purchase_state.mapper.dart @@ -0,0 +1,150 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element + +part of 'purchase_state.dart'; + +class PurchaseStateMapper extends ClassMapperBase { + PurchaseStateMapper._(); + + static PurchaseStateMapper? _instance; + static PurchaseStateMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = PurchaseStateMapper._()); + } + return _instance!; + } + + static T _guard(T Function(MapperContainer) fn) { + ensureInitialized(); + return fn(MapperContainer.globals); + } + + @override + final String id = 'PurchaseState'; + + static Map _$prices(PurchaseState v) => v.prices; + static const Field> _f$prices = + Field('prices', _$prices); + static Map _$purchases(PurchaseState v) => + v.purchases; + static const Field> + _f$purchases = Field('purchases', _$purchases); + static bool _$pending(PurchaseState v) => v.pending; + static const Field _f$pending = + Field('pending', _$pending); + + @override + final Map> fields = const { + #prices: _f$prices, + #purchases: _f$purchases, + #pending: _f$pending, + }; + + static PurchaseState _instantiate(DecodingData data) { + return PurchaseState( + prices: data.dec(_f$prices), + purchases: data.dec(_f$purchases), + pending: data.dec(_f$pending)); + } + + @override + final Function instantiate = _instantiate; + + static PurchaseState fromJson(Map map) { + return _guard((c) => c.fromMap(map)); + } + + static PurchaseState deserialize(String json) { + return _guard((c) => c.fromJson(json)); + } +} + +mixin PurchaseStateMappable { + String serialize() { + return PurchaseStateMapper._guard((c) => c.toJson(this as PurchaseState)); + } + + Map toJson() { + return PurchaseStateMapper._guard((c) => c.toMap(this as PurchaseState)); + } + + PurchaseStateCopyWith + get copyWith => _PurchaseStateCopyWithImpl( + this as PurchaseState, $identity, $identity); + @override + String toString() { + return PurchaseStateMapper._guard((c) => c.asString(this)); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (runtimeType == other.runtimeType && + PurchaseStateMapper._guard((c) => c.isEqual(this, other))); + } + + @override + int get hashCode { + return PurchaseStateMapper._guard((c) => c.hash(this)); + } +} + +extension PurchaseStateValueCopy<$R, $Out> + on ObjectCopyWith<$R, PurchaseState, $Out> { + PurchaseStateCopyWith<$R, PurchaseState, $Out> get $asPurchaseState => + $base.as((v, t, t2) => _PurchaseStateCopyWithImpl(v, t, t2)); +} + +abstract class PurchaseStateCopyWith<$R, $In extends PurchaseState, $Out> + implements ClassCopyWith<$R, $In, $Out> { + MapCopyWith<$R, PurchaseItem, String, ObjectCopyWith<$R, String, String>> + get prices; + MapCopyWith<$R, PurchaseItem, PurchaseDetails, + ObjectCopyWith<$R, PurchaseDetails, PurchaseDetails>> get purchases; + $R call( + {Map? prices, + Map? purchases, + bool? pending}); + PurchaseStateCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t); +} + +class _PurchaseStateCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, PurchaseState, $Out> + implements PurchaseStateCopyWith<$R, PurchaseState, $Out> { + _PurchaseStateCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + PurchaseStateMapper.ensureInitialized(); + @override + MapCopyWith<$R, PurchaseItem, String, ObjectCopyWith<$R, String, String>> + get prices => MapCopyWith($value.prices, + (v, t) => ObjectCopyWith(v, $identity, t), (v) => call(prices: v)); + @override + MapCopyWith<$R, PurchaseItem, PurchaseDetails, + ObjectCopyWith<$R, PurchaseDetails, PurchaseDetails>> + get purchases => MapCopyWith($value.purchases, + (v, t) => ObjectCopyWith(v, $identity, t), (v) => call(purchases: v)); + @override + $R call( + {Map? prices, + Map? purchases, + bool? pending}) => + $apply(FieldCopyWithData({ + if (prices != null) #prices: prices, + if (purchases != null) #purchases: purchases, + if (pending != null) #pending: pending + })); + @override + PurchaseState $make(CopyWithData data) => PurchaseState( + prices: data.get(#prices, or: $value.prices), + purchases: data.get(#purchases, or: $value.purchases), + pending: data.get(#pending, or: $value.pending)); + + @override + PurchaseStateCopyWith<$R2, PurchaseState, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t) => + _PurchaseStateCopyWithImpl($value, $cast, t); +} diff --git a/app/lib/pages/donation/donation_page.dart b/app/lib/pages/donation/donation_page.dart new file mode 100644 index 00000000000..d3ffe344c35 --- /dev/null +++ b/app/lib/pages/donation/donation_page.dart @@ -0,0 +1,110 @@ +import 'package:flutter/material.dart'; +import 'package:localsend_app/gen/strings.g.dart'; +import 'package:localsend_app/model/state/purchase_state.dart'; +import 'package:localsend_app/pages/donation/donation_page_vm.dart'; +import 'package:localsend_app/provider/purchase_provider.dart'; +import 'package:localsend_app/util/native/platform_check.dart'; +import 'package:localsend_app/widget/responsive_list_view.dart'; +import 'package:refena_flutter/refena_flutter.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class DonationPage extends StatelessWidget { + const DonationPage({super.key}); + + @override + Widget build(BuildContext context) { + return ViewModelBuilder( + provider: donationPageVmProvider, + init: (context, ref) => ref.redux(purchaseProvider).dispatchAsync(FetchPricesAndPurchasesAction()), // ignore: discarded_futures + builder: (context, vm) { + return Scaffold( + appBar: AppBar( + title: Text(t.donationPage.title), + ), + body: ResponsiveListView( + padding: const EdgeInsets.symmetric(horizontal: 20), + children: [ + const SizedBox(height: 50), + Center( + child: Text( + t.donationPage.info, + textAlign: TextAlign.center, + ), + ), + const SizedBox(height: 50), + if (vm.purchased.isNotEmpty) + Padding( + padding: const EdgeInsets.only(bottom: 20), + child: Center( + child: Text( + t.donationPage.thanks, + textAlign: TextAlign.center, + style: TextStyle(color: Theme.of(context).colorScheme.primary), + ), + ), + ), + if (checkPlatformSupportPayment()) _StoreDonation(vm) else const _LinkDonation(), + ], + ), + ); + }, + ); + } +} + +class _StoreDonation extends StatelessWidget { + final DonationPageVm vm; + + const _StoreDonation(this.vm); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + ...PurchaseItem.values.map((item) { + return Padding( + padding: const EdgeInsets.only(bottom: 10), + child: FilledButton.icon( + onPressed: vm.purchased.contains(item) ? null : () => vm.purchase(item), + icon: const Icon(Icons.favorite), + label: Text(t.donationPage.donate(amount: vm.prices[item] ?? '...')), + ), + ); + }), + const SizedBox(height: 20), + TextButton.icon( + onPressed: vm.restore, + icon: const Icon(Icons.restore), + label: Text(t.donationPage.restore), + ), + ], + ); + } +} + +class _LinkDonation extends StatelessWidget { + const _LinkDonation(); + + @override + Widget build(BuildContext context) { + return Wrap( + alignment: WrapAlignment.center, + children: [ + TextButton.icon( + onPressed: () async { + await launchUrl(Uri.parse('https://github.com/sponsors/Tienisto'), mode: LaunchMode.externalApplication); + }, + icon: const Icon(Icons.open_in_new), + label: const Text('Github'), + ), + TextButton.icon( + onPressed: () async { + await launchUrl(Uri.parse('https://ko-fi.com/tienisto'), mode: LaunchMode.externalApplication); + }, + icon: const Icon(Icons.open_in_new), + label: const Text('Ko-fi'), + ), + ], + ); + } +} diff --git a/app/lib/pages/donation/donation_page_vm.dart b/app/lib/pages/donation/donation_page_vm.dart new file mode 100644 index 00000000000..b60e22323c0 --- /dev/null +++ b/app/lib/pages/donation/donation_page_vm.dart @@ -0,0 +1,30 @@ +import 'package:localsend_app/model/state/purchase_state.dart'; +import 'package:localsend_app/provider/purchase_provider.dart'; +import 'package:refena_flutter/refena_flutter.dart'; + +class DonationPageVm { + final Map prices; + final Set purchased; + final bool pending; + final void Function(PurchaseItem item) purchase; + final void Function() restore; + + DonationPageVm({ + required this.prices, + required this.purchased, + required this.pending, + required this.purchase, + required this.restore, + }); +} + +final donationPageVmProvider = ViewProvider((ref) { + final state = ref.watch(purchaseProvider); + return DonationPageVm( + prices: state.prices, + purchased: state.purchases.keys.toSet(), + pending: state.pending, + purchase: (item) => ref.redux(purchaseProvider).dispatchAsync(PurchaseAction(item)), + restore: () => ref.redux(purchaseProvider).dispatchAsync(PurchaseRestoreAction()), + ); +}); diff --git a/app/lib/pages/tabs/settings_tab.dart b/app/lib/pages/tabs/settings_tab.dart index b8aedef5c91..42d96c21f4f 100644 --- a/app/lib/pages/tabs/settings_tab.dart +++ b/app/lib/pages/tabs/settings_tab.dart @@ -5,6 +5,7 @@ import 'package:localsend_app/model/device.dart'; import 'package:localsend_app/model/persistence/color_mode.dart'; import 'package:localsend_app/pages/about_page.dart'; import 'package:localsend_app/pages/changelog_page.dart'; +import 'package:localsend_app/pages/donation/donation_page.dart'; import 'package:localsend_app/pages/language_page.dart'; import 'package:localsend_app/pages/tabs/settings_tab_controller.dart'; import 'package:localsend_app/provider/settings_provider.dart'; @@ -22,6 +23,7 @@ import 'package:localsend_app/widget/local_send_logo.dart'; import 'package:localsend_app/widget/responsive_list_view.dart'; import 'package:refena_flutter/refena_flutter.dart'; import 'package:routerino/routerino.dart'; +import 'package:url_launcher/url_launcher.dart'; final _isLinux = checkPlatform([TargetPlatform.linux]); final _isWindows = checkPlatform([TargetPlatform.windows]); @@ -74,24 +76,10 @@ class SettingsTab extends StatelessWidget { onChanged: vm.onChangeColorMode, ), ), - _SettingsEntry( + _ButtonEntry( label: t.settingsTab.general.language, - child: TextButton( - style: TextButton.styleFrom( - backgroundColor: Theme.of(context).inputDecorationTheme.fillColor, - shape: RoundedRectangleBorder(borderRadius: Theme.of(context).inputDecorationTheme.borderRadius), - foregroundColor: Theme.of(context).colorScheme.onSurface, - ), - onPressed: () => vm.onTapLanguage(context), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 5), - child: Text( - vm.settings.locale?.humanName ?? t.settingsTab.general.languageOptions.system, - style: Theme.of(context).textTheme.titleMedium, - textAlign: TextAlign.center, - ), - ), - ), + buttonLabel: vm.settings.locale?.humanName ?? t.settingsTab.general.languageOptions.system, + onTap: () => vm.onTapLanguage(context), ), if (checkPlatformIsDesktop()) ...[ /// Wayland does window position handling, so there's no need for it. See [https://github.com/localsend/localsend/issues/544] @@ -237,7 +225,6 @@ class SettingsTab extends StatelessWidget { ), _SettingsSection( title: t.settingsTab.network.title, - padding: const EdgeInsets.only(bottom: 0), children: [ AnimatedCrossFade( crossFadeState: vm.serverState != null && @@ -397,6 +384,47 @@ class SettingsTab extends StatelessWidget { ), ], ), + _SettingsSection( + title: t.settingsTab.other.title, + padding: const EdgeInsets.only(bottom: 0), + children: [ + _ButtonEntry( + label: 'LocalSend', + buttonLabel: t.settingsTab.other.about, + onTap: () async { + await context.push(() => const AboutPage()); + }, + ), + _ButtonEntry( + label: t.settingsTab.other.support, + buttonLabel: t.settingsTab.other.donate, + onTap: () async { + await context.push(() => const DonationPage()); + }, + ), + _ButtonEntry( + label: t.settingsTab.other.privacyPolicy, + buttonLabel: t.general.open, + onTap: () async { + await launchUrl( + Uri.parse('https://localsend.org/#/privacy'), + mode: LaunchMode.externalApplication, + ); + }, + ), + if (checkPlatform([TargetPlatform.iOS, TargetPlatform.macOS])) + _ButtonEntry( + label: t.settingsTab.other.termsOfUse, + buttonLabel: t.general.open, + onTap: () async { + await launchUrl( + Uri.parse('https://www.apple.com/legal/internet-services/itunes/dev/stdeula/'), + mode: LaunchMode.externalApplication, + ); + }, + ), + ], + ), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ @@ -423,33 +451,16 @@ class SettingsTab extends StatelessWidget { '© ${DateTime.now().year} Tien Do Nam', textAlign: TextAlign.center, ), - const SizedBox(height: 30), - Theme( - data: Theme.of(context).copyWith( - textButtonTheme: TextButtonThemeData( - style: TextButton.styleFrom( - foregroundColor: Theme.of(context).colorScheme.onSurface, - ), + Center( + child: TextButton.icon( + style: TextButton.styleFrom( + foregroundColor: Theme.of(context).colorScheme.onSurface, ), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - TextButton.icon( - onPressed: () async { - await context.push(() => const AboutPage()); - }, - icon: const Icon(Icons.info), - label: Text(t.aboutPage.title), - ), - TextButton.icon( - onPressed: () async { - await context.push(() => const ChangelogPage()); - }, - icon: const Icon(Icons.history), - label: Text(t.changelogPage.title), - ), - ], + onPressed: () async { + await context.push(() => const ChangelogPage()); + }, + icon: const Icon(Icons.history), + label: Text(t.changelogPage.title), ), ), const SizedBox(height: 80), @@ -531,6 +542,42 @@ class _BooleanEntry extends StatelessWidget { } } +/// A specialized version of [_SettingsEntry]. +class _ButtonEntry extends StatelessWidget { + final String label; + final String buttonLabel; + final void Function() onTap; + + const _ButtonEntry({ + required this.label, + required this.buttonLabel, + required this.onTap, + }); + + @override + Widget build(BuildContext context) { + return _SettingsEntry( + label: label, + child: TextButton( + style: TextButton.styleFrom( + backgroundColor: Theme.of(context).inputDecorationTheme.fillColor, + shape: RoundedRectangleBorder(borderRadius: Theme.of(context).inputDecorationTheme.borderRadius), + foregroundColor: Theme.of(context).colorScheme.onSurface, + ), + onPressed: onTap, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 5), + child: Text( + buttonLabel, + style: Theme.of(context).textTheme.titleMedium, + textAlign: TextAlign.center, + ), + ), + ), + ); + } +} + class _SettingsSection extends StatelessWidget { final String title; final List children; diff --git a/app/lib/provider/purchase_provider.dart b/app/lib/provider/purchase_provider.dart new file mode 100644 index 00000000000..45d61d19091 --- /dev/null +++ b/app/lib/provider/purchase_provider.dart @@ -0,0 +1,187 @@ +import 'dart:async'; + +import 'package:collection/collection.dart'; +import 'package:in_app_purchase/in_app_purchase.dart'; +import 'package:localsend_app/model/state/purchase_state.dart'; +import 'package:refena_flutter/refena_flutter.dart'; + +final purchaseProvider = ReduxProvider((ref) { + return PurchaseService(); +}); + +class PurchaseService extends ReduxNotifier { + @override + PurchaseState init() => const PurchaseState( + prices: {}, + purchases: {}, + pending: false, + ); +} + +class InitPurchaseStream extends AsyncReduxAction { + final listening = Completer(); + + @override + Future reduce() async { + Future.delayed(Duration.zero, () => listening.complete()); + await for (final event in InAppPurchase.instance.purchaseStream) { + for (final purchase in event) { + await dispatchAsync(_HandlePurchaseUpdate(purchase)); + } + } + return state; + } +} + +class FetchPricesAndPurchasesAction extends AsyncReduxAction { + @override + Future reduce() async { + if (state.prices.isNotEmpty) { + emitMessage('Already fetched'); + return state; + } + + try { + await dispatchAsync(FetchPricesAction()); + } catch (_) {} + + try { + await dispatchAsync(PurchaseRestoreAction()); + } catch (_) {} + return state; + } +} + +/// Fetches prices for all products. +/// They come from the platform's store and vary by country. +class FetchPricesAction extends AsyncReduxAction { + @override + Future reduce() async { + final response = await InAppPurchase.instance.queryProductDetails(PurchaseItem.values.map((e) => e.platformProductId).toSet()); + final priceMap = {}; + for (final product in response.productDetails) { + final item = PurchaseItem.values.firstWhereOrNull((e) => e.platformProductId == product.id); + if (item == null) { + continue; + } + priceMap[item] = product.price; + } + return state.copyWith( + prices: priceMap, + ); + } +} + +/// Handles the update information triggered by the purchase flow of the platform. +class _HandlePurchaseUpdate extends AsyncReduxAction { + final PurchaseDetails purchase; + + _HandlePurchaseUpdate(this.purchase); + + @override + bool get trackOrigin => false; + + @override + Future reduce() async { + if (purchase.status == PurchaseStatus.pending) { + return state.copyWith(pending: true); + } else { + dispatch(_SetPendingAction(false)); + } + + if (purchase.status == PurchaseStatus.error) { + // ignore: avoid_print + throw 'Error purchasing: ${purchase.error?.message}'; + } else if (purchase.status == PurchaseStatus.purchased || purchase.status == PurchaseStatus.restored) { + final purchaseEnum = PurchaseItem.values.firstWhereOrNull((element) => element.platformProductId == purchase.productID); + if (purchaseEnum == null) { + throw 'Unknown product ID: ${purchase.productID}'; + } + dispatch(AddPurchaseAction(purchaseEnum, purchase)); + } + + if (purchase.pendingCompletePurchase) { + // No need to verify. It's just a donation... + await InAppPurchase.instance.completePurchase(purchase); + } + + return state; + } + + @override + String get debugLabel => 'HandlePurchaseUpdate(${purchase.status}, ${purchase.productID})'; +} + +class AddPurchaseAction extends ReduxAction { + final PurchaseItem item; + final PurchaseDetails purchase; + + AddPurchaseAction(this.item, this.purchase); + + @override + PurchaseState reduce() { + return state.copyWith( + purchases: { + ...state.purchases, + item: purchase, + }, + ); + } +} + +class _SetPendingAction extends ReduxAction { + final bool pending; + + _SetPendingAction(this.pending); + + @override + PurchaseState reduce() => state.copyWith(pending: pending); +} + +/// Action to restore purchases. +/// Dispatched on first app start or manually by the user. +class PurchaseRestoreAction extends AsyncReduxAction { + @override + Future reduce() async { + try { + await InAppPurchase.instance.restorePurchases(); + } catch (_) {} + return state; + } +} + +/// Action to reset the purchase state. +/// Only used for testing. +class PurchaseResetAction extends ReduxAction { + @override + PurchaseState reduce() => state.copyWith( + purchases: {}, + pending: false, + ); +} + +/// Initiate the purchase flow for a product. +/// The actual callbacks are handled by [_HandlePurchaseUpdate]. +class PurchaseAction extends AsyncReduxAction { + final PurchaseItem item; + + PurchaseAction(this.item); + + @override + Future reduce() async { + final response = await InAppPurchase.instance.queryProductDetails({item.platformProductId}); + final productDetails = response.productDetails.firstOrNull; + if (productDetails == null) { + throw Exception('Product not found: ${item.platformProductId}'); + } + + // TODO: Handle changing subscriptions if subscriptions would be added + await InAppPurchase.instance.buyNonConsumable( + purchaseParam: PurchaseParam(productDetails: productDetails), + ); + return state; + } + + @override + String get debugLabel => 'BuyAction(${item.name})'; +} diff --git a/app/lib/util/native/platform_check.dart b/app/lib/util/native/platform_check.dart index 86e84d29186..782923b1d34 100644 --- a/app/lib/util/native/platform_check.dart +++ b/app/lib/util/native/platform_check.dart @@ -54,3 +54,8 @@ bool checkPlatformIsNotWaylandDesktop() { } return true; } + +/// This platform supports payment (in-app purchase) +bool checkPlatformSupportPayment() { + return checkPlatform([TargetPlatform.android, TargetPlatform.iOS, TargetPlatform.macOS]); +} diff --git a/app/macos/Flutter/GeneratedPluginRegistrant.swift b/app/macos/Flutter/GeneratedPluginRegistrant.swift index 60fb281d56f..793aa288e5f 100644 --- a/app/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/app/macos/Flutter/GeneratedPluginRegistrant.swift @@ -11,6 +11,7 @@ import device_info_plus import dynamic_color import file_selector_macos import gal +import in_app_purchase_storekit import network_info_plus import package_info_plus import pasteboard @@ -32,6 +33,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) GalPlugin.register(with: registry.registrar(forPlugin: "GalPlugin")) + InAppPurchasePlugin.register(with: registry.registrar(forPlugin: "InAppPurchasePlugin")) NetworkInfoPlusPlugin.register(with: registry.registrar(forPlugin: "NetworkInfoPlusPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin")) diff --git a/app/macos/Podfile.lock b/app/macos/Podfile.lock index 13e6233cf30..def53945946 100644 --- a/app/macos/Podfile.lock +++ b/app/macos/Podfile.lock @@ -14,6 +14,9 @@ PODS: - gal (1.0.0): - Flutter - FlutterMacOS + - in_app_purchase_storekit (0.0.1): + - Flutter + - FlutterMacOS - network_info_plus (0.0.1): - FlutterMacOS - package_info_plus (0.0.1): @@ -54,6 +57,7 @@ DEPENDENCIES: - file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`) - FlutterMacOS (from `Flutter/ephemeral`) - gal (from `Flutter/ephemeral/.symlinks/plugins/gal/darwin`) + - in_app_purchase_storekit (from `Flutter/ephemeral/.symlinks/plugins/in_app_purchase_storekit/darwin`) - network_info_plus (from `Flutter/ephemeral/.symlinks/plugins/network_info_plus/macos`) - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) - pasteboard (from `Flutter/ephemeral/.symlinks/plugins/pasteboard/macos`) @@ -87,6 +91,8 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral gal: :path: Flutter/ephemeral/.symlinks/plugins/gal/darwin + in_app_purchase_storekit: + :path: Flutter/ephemeral/.symlinks/plugins/in_app_purchase_storekit/darwin network_info_plus: :path: Flutter/ephemeral/.symlinks/plugins/network_info_plus/macos package_info_plus: @@ -122,6 +128,7 @@ SPEC CHECKSUMS: file_selector_macos: 468fb6b81fac7c0e88d71317f3eec34c3b008ff9 FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 gal: 61e868295d28fe67ffa297fae6dacebf56fd53e1 + in_app_purchase_storekit: 4fb7ee9e824b1f09107fbfbbce8c4b276366dc43 network_info_plus: f4fbc7877ab7b3294500d9441dfa53cd54972d05 package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce pasteboard: 9b69dba6fedbb04866be632205d532fe2f6b1d99 diff --git a/app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 1011138274f..664dcdec0c1 100644 --- a/app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -59,6 +59,9 @@ ReferencedContainer = "container:Runner.xcodeproj"> + + + + diff --git a/app/pubspec.lock b/app/pubspec.lock index e417ca422c8..88ff2f04c88 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -700,6 +700,38 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.1+1" + in_app_purchase: + dependency: "direct main" + description: + name: in_app_purchase + sha256: bdda02b5b11b56d5e29c7f0c57c433db3452b0c8ce1c37cbfcf1de52946efd9f + url: "https://pub.dev" + source: hosted + version: "3.1.11" + in_app_purchase_android: + dependency: transitive + description: + name: in_app_purchase_android + sha256: c4b84caa4e2c7ffebda444c5033fd8423cc3a45a6e1066929bbbcd4daf665db5 + url: "https://pub.dev" + source: hosted + version: "0.3.0+15" + in_app_purchase_platform_interface: + dependency: transitive + description: + name: in_app_purchase_platform_interface + sha256: "5168afbc54f406f741252b66d41872c1193a0066a6edcb587176290b92e2d537" + url: "https://pub.dev" + source: hosted + version: "1.3.6" + in_app_purchase_storekit: + dependency: transitive + description: + name: in_app_purchase_storekit + sha256: "29526f5ce85bd908b4cacdadb2e8ef299bccbb516b90d2881805343f868502ab" + url: "https://pub.dev" + source: hosted + version: "0.3.7" intl: dependency: "direct main" description: diff --git a/app/pubspec.yaml b/app/pubspec.yaml index b4db64efdf7..26f4ab63a47 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -31,6 +31,7 @@ dependencies: flutter_markdown: 0.6.18 gal: 2.1.2 image_picker: 1.0.4 + in_app_purchase: 3.1.11 intl: ^0.18.0 # allow newer versions, so it can compile with newer Flutter versions launch_at_startup: 0.2.2 logging: 1.2.0 From 1b42c522860d79aa1c0a727f712420bd66470c30 Mon Sep 17 00:00:00 2001 From: Tien Do Nam Date: Sat, 18 Nov 2023 17:25:23 +0100 Subject: [PATCH 22/31] feat: show loading screen during donation --- app/lib/pages/donation/donation_page.dart | 45 ++++++++++++++--------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/app/lib/pages/donation/donation_page.dart b/app/lib/pages/donation/donation_page.dart index d3ffe344c35..725f6830d97 100644 --- a/app/lib/pages/donation/donation_page.dart +++ b/app/lib/pages/donation/donation_page.dart @@ -21,29 +21,40 @@ class DonationPage extends StatelessWidget { appBar: AppBar( title: Text(t.donationPage.title), ), - body: ResponsiveListView( - padding: const EdgeInsets.symmetric(horizontal: 20), + body: Stack( children: [ - const SizedBox(height: 50), - Center( - child: Text( - t.donationPage.info, - textAlign: TextAlign.center, - ), - ), - const SizedBox(height: 50), - if (vm.purchased.isNotEmpty) - Padding( - padding: const EdgeInsets.only(bottom: 20), - child: Center( + ResponsiveListView( + padding: const EdgeInsets.symmetric(horizontal: 20), + children: [ + const SizedBox(height: 50), + Center( child: Text( - t.donationPage.thanks, + t.donationPage.info, textAlign: TextAlign.center, - style: TextStyle(color: Theme.of(context).colorScheme.primary), ), ), + const SizedBox(height: 50), + if (vm.purchased.isNotEmpty) + Padding( + padding: const EdgeInsets.only(bottom: 20), + child: Center( + child: Text( + t.donationPage.thanks, + textAlign: TextAlign.center, + style: TextStyle(color: Theme.of(context).colorScheme.primary), + ), + ), + ), + if (checkPlatformSupportPayment()) _StoreDonation(vm) else const _LinkDonation(), + ], + ), + if (vm.pending) + Container( + color: Colors.black.withOpacity(0.1), + child: const Center( + child: CircularProgressIndicator(), + ), ), - if (checkPlatformSupportPayment()) _StoreDonation(vm) else const _LinkDonation(), ], ), ); From f8605fe8ee464615655de3299cf78e4a445feb94 Mon Sep 17 00:00:00 2001 From: Tien Do Nam Date: Sat, 18 Nov 2023 17:28:10 +0100 Subject: [PATCH 23/31] i18n: update strings --- app/assets/i18n/_missing_translations_ar.json | 1 - app/assets/i18n/_missing_translations_bn.json | 1 - app/assets/i18n/_missing_translations_ca.json | 1 - app/assets/i18n/_missing_translations_cs.json | 1 - app/assets/i18n/_missing_translations_el.json | 1 - app/assets/i18n/_missing_translations_es_ES.json | 1 - app/assets/i18n/_missing_translations_eu.json | 1 - app/assets/i18n/_missing_translations_fa.json | 1 - app/assets/i18n/_missing_translations_fil_PH.json | 1 - app/assets/i18n/_missing_translations_fr_FR.json | 1 - app/assets/i18n/_missing_translations_he.json | 1 - app/assets/i18n/_missing_translations_hu.json | 1 - app/assets/i18n/_missing_translations_id.json | 1 - app/assets/i18n/_missing_translations_it.json | 1 - app/assets/i18n/_missing_translations_ja.json | 1 - app/assets/i18n/_missing_translations_km.json | 1 - app/assets/i18n/_missing_translations_ko.json | 1 - app/assets/i18n/_missing_translations_ne.json | 1 - app/assets/i18n/_missing_translations_nl.json | 1 - app/assets/i18n/_missing_translations_pl.json | 1 - app/assets/i18n/_missing_translations_pt_BR.json | 1 - app/assets/i18n/_missing_translations_ru.json | 1 - app/assets/i18n/_missing_translations_sv.json | 1 - app/assets/i18n/_missing_translations_th.json | 1 - app/assets/i18n/_missing_translations_tr.json | 1 - app/assets/i18n/_missing_translations_uk.json | 1 - app/assets/i18n/_missing_translations_ur.json | 1 - app/assets/i18n/_missing_translations_vi.json | 1 - app/assets/i18n/_missing_translations_zh_CN.json | 1 - app/assets/i18n/_missing_translations_zh_HK.json | 1 - app/assets/i18n/_missing_translations_zh_TW.json | 1 - app/assets/i18n/strings.i18n.json | 1 - app/assets/i18n/strings_de.i18n.json | 1 - app/lib/gen/strings.g.dart | 2 +- app/lib/gen/strings_de.g.dart | 1 - app/lib/gen/strings_en.g.dart | 1 - app/lib/pages/tabs/settings_tab.dart | 4 ++-- 37 files changed, 3 insertions(+), 38 deletions(-) diff --git a/app/assets/i18n/_missing_translations_ar.json b/app/assets/i18n/_missing_translations_ar.json index 163785c47ec..5c72bed7cae 100644 --- a/app/assets/i18n/_missing_translations_ar.json +++ b/app/assets/i18n/_missing_translations_ar.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_bn.json b/app/assets/i18n/_missing_translations_bn.json index 645fa477de0..5ccaf2c092b 100644 --- a/app/assets/i18n/_missing_translations_bn.json +++ b/app/assets/i18n/_missing_translations_bn.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_ca.json b/app/assets/i18n/_missing_translations_ca.json index 3aa994d8302..6134615f5dc 100644 --- a/app/assets/i18n/_missing_translations_ca.json +++ b/app/assets/i18n/_missing_translations_ca.json @@ -20,7 +20,6 @@ }, "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_cs.json b/app/assets/i18n/_missing_translations_cs.json index 0219bd47453..07659d50bea 100644 --- a/app/assets/i18n/_missing_translations_cs.json +++ b/app/assets/i18n/_missing_translations_cs.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_el.json b/app/assets/i18n/_missing_translations_el.json index d2f2657290c..71e66ce42d9 100644 --- a/app/assets/i18n/_missing_translations_el.json +++ b/app/assets/i18n/_missing_translations_el.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_es_ES.json b/app/assets/i18n/_missing_translations_es_ES.json index 72c0c0a8adb..26cd38fc40c 100644 --- a/app/assets/i18n/_missing_translations_es_ES.json +++ b/app/assets/i18n/_missing_translations_es_ES.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_eu.json b/app/assets/i18n/_missing_translations_eu.json index 99ba663a38c..843a7f65a1d 100644 --- a/app/assets/i18n/_missing_translations_eu.json +++ b/app/assets/i18n/_missing_translations_eu.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_fa.json b/app/assets/i18n/_missing_translations_fa.json index 8789913cb36..18d925f1f88 100644 --- a/app/assets/i18n/_missing_translations_fa.json +++ b/app/assets/i18n/_missing_translations_fa.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_fil_PH.json b/app/assets/i18n/_missing_translations_fil_PH.json index e6174e5fe3a..d67d602938c 100644 --- a/app/assets/i18n/_missing_translations_fil_PH.json +++ b/app/assets/i18n/_missing_translations_fil_PH.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_fr_FR.json b/app/assets/i18n/_missing_translations_fr_FR.json index 8f849314554..c0ada858042 100644 --- a/app/assets/i18n/_missing_translations_fr_FR.json +++ b/app/assets/i18n/_missing_translations_fr_FR.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_he.json b/app/assets/i18n/_missing_translations_he.json index edb887a539e..6c0b17dc9a0 100644 --- a/app/assets/i18n/_missing_translations_he.json +++ b/app/assets/i18n/_missing_translations_he.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_hu.json b/app/assets/i18n/_missing_translations_hu.json index 60185510017..caf78efae45 100644 --- a/app/assets/i18n/_missing_translations_hu.json +++ b/app/assets/i18n/_missing_translations_hu.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_id.json b/app/assets/i18n/_missing_translations_id.json index aff018b97ee..38ec6dfe753 100644 --- a/app/assets/i18n/_missing_translations_id.json +++ b/app/assets/i18n/_missing_translations_id.json @@ -20,7 +20,6 @@ }, "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_it.json b/app/assets/i18n/_missing_translations_it.json index 0702cd1d30b..e175390dc7b 100644 --- a/app/assets/i18n/_missing_translations_it.json +++ b/app/assets/i18n/_missing_translations_it.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_ja.json b/app/assets/i18n/_missing_translations_ja.json index a9d88d1d609..5c2398a4633 100644 --- a/app/assets/i18n/_missing_translations_ja.json +++ b/app/assets/i18n/_missing_translations_ja.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_km.json b/app/assets/i18n/_missing_translations_km.json index a6bb8d9c398..c18908ce4d8 100644 --- a/app/assets/i18n/_missing_translations_km.json +++ b/app/assets/i18n/_missing_translations_km.json @@ -15,7 +15,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_ko.json b/app/assets/i18n/_missing_translations_ko.json index 29776cf45ff..a23c5f94e24 100644 --- a/app/assets/i18n/_missing_translations_ko.json +++ b/app/assets/i18n/_missing_translations_ko.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_ne.json b/app/assets/i18n/_missing_translations_ne.json index e030c8c2a59..cc954088362 100644 --- a/app/assets/i18n/_missing_translations_ne.json +++ b/app/assets/i18n/_missing_translations_ne.json @@ -20,7 +20,6 @@ }, "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_nl.json b/app/assets/i18n/_missing_translations_nl.json index 8be292e789b..ef501965f49 100644 --- a/app/assets/i18n/_missing_translations_nl.json +++ b/app/assets/i18n/_missing_translations_nl.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_pl.json b/app/assets/i18n/_missing_translations_pl.json index b79825868ac..16ede6c70f5 100644 --- a/app/assets/i18n/_missing_translations_pl.json +++ b/app/assets/i18n/_missing_translations_pl.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_pt_BR.json b/app/assets/i18n/_missing_translations_pt_BR.json index e09a8fcbc4a..b685046d346 100644 --- a/app/assets/i18n/_missing_translations_pt_BR.json +++ b/app/assets/i18n/_missing_translations_pt_BR.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_ru.json b/app/assets/i18n/_missing_translations_ru.json index 6f53b5bc463..62fc9918e57 100644 --- a/app/assets/i18n/_missing_translations_ru.json +++ b/app/assets/i18n/_missing_translations_ru.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_sv.json b/app/assets/i18n/_missing_translations_sv.json index 6d3f9a58d20..97c3c826c53 100644 --- a/app/assets/i18n/_missing_translations_sv.json +++ b/app/assets/i18n/_missing_translations_sv.json @@ -20,7 +20,6 @@ }, "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_th.json b/app/assets/i18n/_missing_translations_th.json index 5f63ac868be..617e619a72d 100644 --- a/app/assets/i18n/_missing_translations_th.json +++ b/app/assets/i18n/_missing_translations_th.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_tr.json b/app/assets/i18n/_missing_translations_tr.json index 5bb50bcb31d..1a08f34b556 100644 --- a/app/assets/i18n/_missing_translations_tr.json +++ b/app/assets/i18n/_missing_translations_tr.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_uk.json b/app/assets/i18n/_missing_translations_uk.json index e2fb4a198b5..b6487ec1d24 100644 --- a/app/assets/i18n/_missing_translations_uk.json +++ b/app/assets/i18n/_missing_translations_uk.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_ur.json b/app/assets/i18n/_missing_translations_ur.json index 559970455ae..74ff5694dd4 100644 --- a/app/assets/i18n/_missing_translations_ur.json +++ b/app/assets/i18n/_missing_translations_ur.json @@ -20,7 +20,6 @@ }, "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_vi.json b/app/assets/i18n/_missing_translations_vi.json index 118698ef630..f72418e4acc 100644 --- a/app/assets/i18n/_missing_translations_vi.json +++ b/app/assets/i18n/_missing_translations_vi.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_zh_CN.json b/app/assets/i18n/_missing_translations_zh_CN.json index a30d5ceb6b4..5f78e1e7f25 100644 --- a/app/assets/i18n/_missing_translations_zh_CN.json +++ b/app/assets/i18n/_missing_translations_zh_CN.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_zh_HK.json b/app/assets/i18n/_missing_translations_zh_HK.json index fc6fcdbb1f0..88bdc1d7ae6 100644 --- a/app/assets/i18n/_missing_translations_zh_HK.json +++ b/app/assets/i18n/_missing_translations_zh_HK.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/_missing_translations_zh_TW.json b/app/assets/i18n/_missing_translations_zh_TW.json index 05e1acd35f5..e92f138642f 100644 --- a/app/assets/i18n/_missing_translations_zh_TW.json +++ b/app/assets/i18n/_missing_translations_zh_TW.json @@ -6,7 +6,6 @@ "settingsTab": { "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/strings.i18n.json b/app/assets/i18n/strings.i18n.json index d5295599554..50e650cc00f 100644 --- a/app/assets/i18n/strings.i18n.json +++ b/app/assets/i18n/strings.i18n.json @@ -125,7 +125,6 @@ }, "other": { "title": "Other", - "about": "About", "support": "Support LocalSend", "donate": "Donate", "privacyPolicy": "Privacy Policy", diff --git a/app/assets/i18n/strings_de.i18n.json b/app/assets/i18n/strings_de.i18n.json index d5ff2249437..a2b667e67e9 100644 --- a/app/assets/i18n/strings_de.i18n.json +++ b/app/assets/i18n/strings_de.i18n.json @@ -125,7 +125,6 @@ }, "other": { "title": "Weitere", - "about": "Über", "support": "LocalSend unterstützen", "donate": "Spenden", "privacyPolicy": "Datenschutzerklärung", diff --git a/app/lib/gen/strings.g.dart b/app/lib/gen/strings.g.dart index 5bf842bf072..d26b76480cc 100644 --- a/app/lib/gen/strings.g.dart +++ b/app/lib/gen/strings.g.dart @@ -4,7 +4,7 @@ /// To regenerate, run: `dart run slang` /// /// Locales: 33 -/// Strings: 8934 (270 per locale) +/// Strings: 8932 (270 per locale) // coverage:ignore-file diff --git a/app/lib/gen/strings_de.g.dart b/app/lib/gen/strings_de.g.dart index 627d0e0256a..4e4bd081e90 100644 --- a/app/lib/gen/strings_de.g.dart +++ b/app/lib/gen/strings_de.g.dart @@ -518,7 +518,6 @@ class _StringsSettingsTabOtherDe extends _StringsSettingsTabOtherEn { // Translations @override String get title => 'Weitere'; - @override String get about => 'Über'; @override String get support => 'LocalSend unterstützen'; @override String get donate => 'Spenden'; @override String get privacyPolicy => 'Datenschutzerklärung'; diff --git a/app/lib/gen/strings_en.g.dart b/app/lib/gen/strings_en.g.dart index 02ded6f7380..cfd6bb2f699 100644 --- a/app/lib/gen/strings_en.g.dart +++ b/app/lib/gen/strings_en.g.dart @@ -588,7 +588,6 @@ class _StringsSettingsTabOtherEn { // Translations String get title => 'Other'; - String get about => 'About'; String get support => 'Support LocalSend'; String get donate => 'Donate'; String get privacyPolicy => 'Privacy Policy'; diff --git a/app/lib/pages/tabs/settings_tab.dart b/app/lib/pages/tabs/settings_tab.dart index 42d96c21f4f..493c35834c6 100644 --- a/app/lib/pages/tabs/settings_tab.dart +++ b/app/lib/pages/tabs/settings_tab.dart @@ -389,8 +389,8 @@ class SettingsTab extends StatelessWidget { padding: const EdgeInsets.only(bottom: 0), children: [ _ButtonEntry( - label: 'LocalSend', - buttonLabel: t.settingsTab.other.about, + label: t.aboutPage.title, + buttonLabel: t.general.open, onTap: () async { await context.push(() => const AboutPage()); }, From da473f008e699f9298b2e907498bf3979b5a0d80 Mon Sep 17 00:00:00 2001 From: Farshad Gh <53800521+farshad991@users.noreply.github.com> Date: Sun, 19 Nov 2023 01:52:45 +0330 Subject: [PATCH 24/31] Update _missing_translations_fa.json (#911) --- app/assets/i18n/_missing_translations_fa.json | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/assets/i18n/_missing_translations_fa.json b/app/assets/i18n/_missing_translations_fa.json index 18d925f1f88..3dacae01aaa 100644 --- a/app/assets/i18n/_missing_translations_fa.json +++ b/app/assets/i18n/_missing_translations_fa.json @@ -5,18 +5,18 @@ ], "settingsTab": { "other": { - "title": "Other", - "support": "Support LocalSend", - "donate": "Donate", - "privacyPolicy": "Privacy Policy", - "termsOfUse": "Terms of Use" + "title": "سایر", + "support": "حمایت از لوکال‌سند", + "donate": "کمک مالی", + "privacyPolicy": "سیاست حفظ حریم خصوصی", + "termsOfUse": "شرایط استفاده" } }, "donationPage": { - "title": "Donate", - "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", - "donate": "Donate {amount}", - "thanks": "Thank you very much!", - "restore": "Restore purchase" + "title": "کمک مالی", + "info": "لوکال‌سند رایگان، متن باز و فاقد هر گونه تبلیغات است. اگر به این برنامه علاقه‌مندید، می توانید با کمک مالی از توسعه آن حمایت کنید", + "donate": "کمک مالی {amount}", + "thanks": "بسیار از شما سپاسگزاریم", + "restore": "بازیابی خرید" } } From 3276df83b1a38bf071167750e5632755094ad71d Mon Sep 17 00:00:00 2001 From: Tien Do Nam Date: Sat, 18 Nov 2023 23:43:39 +0100 Subject: [PATCH 25/31] docs: update changelog --- app/assets/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/assets/CHANGELOG.md b/app/assets/CHANGELOG.md index 9e433fe5fe0..d1130841917 100644 --- a/app/assets/CHANGELOG.md +++ b/app/assets/CHANGELOG.md @@ -2,6 +2,8 @@ - feat: ignore duplicate files when selected from file picker (@programmermager) - feat: add donation options (@Tienisto) +- feat(macos): add Command+W shortcut to close the window (@Q1CHENL) +- fix: also show an OLED color mode option when dynamic colors are not supported by OS (@dhruvanbhalara) - i18n: add Greek (@multipetros) ## 1.12.0 (2023-10-25) From de2ae7b2631b44868ed392997643830b6ca5b331 Mon Sep 17 00:00:00 2001 From: Tien Do Nam Date: Sun, 19 Nov 2023 00:20:47 +0100 Subject: [PATCH 26/31] chore: update storekit --- app/ios/MyLocalSendStoreKit.storekit | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/ios/MyLocalSendStoreKit.storekit b/app/ios/MyLocalSendStoreKit.storekit index ea71637c6ec..bc3b7119ba8 100644 --- a/app/ios/MyLocalSendStoreKit.storekit +++ b/app/ios/MyLocalSendStoreKit.storekit @@ -5,7 +5,7 @@ ], "products" : [ { - "displayPrice" : "4.0", + "displayPrice" : "5.0", "familyShareable" : false, "internalID" : "6472594578", "localizations" : [ @@ -20,7 +20,7 @@ "type" : "NonConsumable" }, { - "displayPrice" : "9.0", + "displayPrice" : "10.0", "familyShareable" : false, "internalID" : "6472594779", "localizations" : [ @@ -35,7 +35,7 @@ "type" : "NonConsumable" }, { - "displayPrice" : "18.0", + "displayPrice" : "20.0", "familyShareable" : false, "internalID" : "6472594819", "localizations" : [ @@ -50,7 +50,7 @@ "type" : "NonConsumable" }, { - "displayPrice" : "45.0", + "displayPrice" : "50.0", "familyShareable" : false, "internalID" : "6472595571", "localizations" : [ @@ -69,7 +69,7 @@ "_applicationInternalID" : "1661733229", "_developerTeamID" : "3W7H4PYMCV", "_failTransactionsEnabled" : false, - "_lastSynchronizedDate" : 722014387.19710302, + "_lastSynchronizedDate" : 722042011.75185394, "_locale" : "en_US", "_storefront" : "USA", "_storeKitErrors" : [ From 92be9028eaaef0046a65e27a275b3c727a565a41 Mon Sep 17 00:00:00 2001 From: Tien Do Nam Date: Sun, 19 Nov 2023 01:02:09 +0100 Subject: [PATCH 27/31] feat: update about page --- CONTRIBUTING.md | 26 +---------- app/assets/i18n/_missing_translations_ar.json | 9 ++++ app/assets/i18n/_missing_translations_bn.json | 9 ++++ app/assets/i18n/_missing_translations_ca.json | 9 ++++ app/assets/i18n/_missing_translations_cs.json | 9 ++++ app/assets/i18n/_missing_translations_el.json | 9 ++++ .../i18n/_missing_translations_es_ES.json | 9 ++++ app/assets/i18n/_missing_translations_eu.json | 9 ++++ app/assets/i18n/_missing_translations_fa.json | 29 +++++++----- .../i18n/_missing_translations_fil_PH.json | 9 ++++ .../i18n/_missing_translations_fr_FR.json | 9 ++++ app/assets/i18n/_missing_translations_he.json | 9 ++++ app/assets/i18n/_missing_translations_hu.json | 9 ++++ app/assets/i18n/_missing_translations_id.json | 9 ++++ app/assets/i18n/_missing_translations_it.json | 9 ++++ app/assets/i18n/_missing_translations_ja.json | 9 ++++ app/assets/i18n/_missing_translations_km.json | 9 ++++ app/assets/i18n/_missing_translations_ko.json | 9 ++++ app/assets/i18n/_missing_translations_ne.json | 9 ++++ app/assets/i18n/_missing_translations_nl.json | 9 ++++ app/assets/i18n/_missing_translations_pl.json | 9 ++++ .../i18n/_missing_translations_pt_BR.json | 9 ++++ app/assets/i18n/_missing_translations_ru.json | 9 ++++ app/assets/i18n/_missing_translations_sv.json | 9 ++++ app/assets/i18n/_missing_translations_th.json | 9 ++++ app/assets/i18n/_missing_translations_tr.json | 9 ++++ app/assets/i18n/_missing_translations_uk.json | 9 ++++ app/assets/i18n/_missing_translations_ur.json | 9 ++++ app/assets/i18n/_missing_translations_vi.json | 9 ++++ .../i18n/_missing_translations_zh_CN.json | 9 ++++ .../i18n/_missing_translations_zh_HK.json | 9 ++++ .../i18n/_missing_translations_zh_TW.json | 9 ++++ app/assets/i18n/strings.i18n.json | 9 +++- app/assets/i18n/strings_de.i18n.json | 9 +++- app/lib/gen/strings.g.dart | 2 +- app/lib/gen/strings_de.g.dart | 7 +++ app/lib/gen/strings_en.g.dart | 7 +++ app/lib/pages/{ => about}/about_page.dart | 45 +++++++++++++------ app/lib/pages/about/contributors.dart | 7 +++ app/lib/pages/about/translators.dart | 29 ++++++++++++ app/lib/pages/tabs/settings_tab.dart | 2 +- 41 files changed, 389 insertions(+), 53 deletions(-) rename app/lib/pages/{ => about}/about_page.dart (67%) create mode 100644 app/lib/pages/about/contributors.dart create mode 100644 app/lib/pages/about/translators.dart diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6b4ff3eacf7..ed40b49be2e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,31 +33,7 @@ You can help in translating this app to other languages! **_Take note:_ Fields decorated with `@` are not meant to be translated, they are not used in the app in any way, being merely informative text about the file or to give context to the translator.** -Thanks to all translators! - -| Language | Translators | -|---------------------|------------------------------------| -| Czech | @Amereyeu | -| German | Tien Do Nam (@Tienisto) | -| Italian | @Francesco146 | -| Greek | Petros Kyladitis (@multipetros) | -| Spanish | Esteban Daniel Saracho (@esaracho) | -| Persian | @farshad991 | -| French | @Nixuge | -| Hungarian | @gidano | -| Hebrew | @ShlomoCode | -| Japanese | @soya-daizu | -| Khmer | Chandara H. Wei (@nidexingg) | -| Korean | @mgmix | -| Russian | Sergiy (@sergd88) | -| Ukrainian | Sergiy (@sergd88) | -| Vietnamese | @faea726 | -| Chinese (China) | @nkh0472, @graphemecluster | -| Chinese (Hong Kong) | @graphemecluster | -| Chinese (Taiwan) | @Neo1102, @graphemecluster | -| Bangla | @RishiASheth | - -Your name is missing? Please open a pull request! +Thanks to all [translators](https://github.com/localsend/localsend/tree/main/app/lib/pages/about/translators.dart)! ## Contributing Guidelines diff --git a/app/assets/i18n/_missing_translations_ar.json b/app/assets/i18n/_missing_translations_ar.json index 5c72bed7cae..f2eceb90337 100644 --- a/app/assets/i18n/_missing_translations_ar.json +++ b/app/assets/i18n/_missing_translations_ar.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_bn.json b/app/assets/i18n/_missing_translations_bn.json index 5ccaf2c092b..c0b423596c1 100644 --- a/app/assets/i18n/_missing_translations_bn.json +++ b/app/assets/i18n/_missing_translations_bn.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_ca.json b/app/assets/i18n/_missing_translations_ca.json index 6134615f5dc..b8ddfb52a30 100644 --- a/app/assets/i18n/_missing_translations_ca.json +++ b/app/assets/i18n/_missing_translations_ca.json @@ -26,6 +26,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_cs.json b/app/assets/i18n/_missing_translations_cs.json index 07659d50bea..595c3a43f4e 100644 --- a/app/assets/i18n/_missing_translations_cs.json +++ b/app/assets/i18n/_missing_translations_cs.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_el.json b/app/assets/i18n/_missing_translations_el.json index 71e66ce42d9..ce02337e808 100644 --- a/app/assets/i18n/_missing_translations_el.json +++ b/app/assets/i18n/_missing_translations_el.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_es_ES.json b/app/assets/i18n/_missing_translations_es_ES.json index 26cd38fc40c..5adb262dfcd 100644 --- a/app/assets/i18n/_missing_translations_es_ES.json +++ b/app/assets/i18n/_missing_translations_es_ES.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_eu.json b/app/assets/i18n/_missing_translations_eu.json index 843a7f65a1d..f1e25e26567 100644 --- a/app/assets/i18n/_missing_translations_eu.json +++ b/app/assets/i18n/_missing_translations_eu.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_fa.json b/app/assets/i18n/_missing_translations_fa.json index 3dacae01aaa..03e14fd727e 100644 --- a/app/assets/i18n/_missing_translations_fa.json +++ b/app/assets/i18n/_missing_translations_fa.json @@ -5,18 +5,27 @@ ], "settingsTab": { "other": { - "title": "سایر", - "support": "حمایت از لوکال‌سند", - "donate": "کمک مالی", - "privacyPolicy": "سیاست حفظ حریم خصوصی", - "termsOfUse": "شرایط استفاده" + "title": "Other", + "support": "Support LocalSend", + "donate": "Donate", + "privacyPolicy": "Privacy Policy", + "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { - "title": "کمک مالی", - "info": "لوکال‌سند رایگان، متن باز و فاقد هر گونه تبلیغات است. اگر به این برنامه علاقه‌مندید، می توانید با کمک مالی از توسعه آن حمایت کنید", - "donate": "کمک مالی {amount}", - "thanks": "بسیار از شما سپاسگزاریم", - "restore": "بازیابی خرید" + "title": "Donate", + "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", + "donate": "Donate {amount}", + "thanks": "Thank you very much!", + "restore": "Restore purchase" } } diff --git a/app/assets/i18n/_missing_translations_fil_PH.json b/app/assets/i18n/_missing_translations_fil_PH.json index d67d602938c..5d32eea4c47 100644 --- a/app/assets/i18n/_missing_translations_fil_PH.json +++ b/app/assets/i18n/_missing_translations_fil_PH.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_fr_FR.json b/app/assets/i18n/_missing_translations_fr_FR.json index c0ada858042..a00873560fb 100644 --- a/app/assets/i18n/_missing_translations_fr_FR.json +++ b/app/assets/i18n/_missing_translations_fr_FR.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_he.json b/app/assets/i18n/_missing_translations_he.json index 6c0b17dc9a0..a4adcf1dfe7 100644 --- a/app/assets/i18n/_missing_translations_he.json +++ b/app/assets/i18n/_missing_translations_he.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_hu.json b/app/assets/i18n/_missing_translations_hu.json index caf78efae45..85a8425761a 100644 --- a/app/assets/i18n/_missing_translations_hu.json +++ b/app/assets/i18n/_missing_translations_hu.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_id.json b/app/assets/i18n/_missing_translations_id.json index 38ec6dfe753..1a161932f4b 100644 --- a/app/assets/i18n/_missing_translations_id.json +++ b/app/assets/i18n/_missing_translations_id.json @@ -26,6 +26,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_it.json b/app/assets/i18n/_missing_translations_it.json index e175390dc7b..43de93b0d65 100644 --- a/app/assets/i18n/_missing_translations_it.json +++ b/app/assets/i18n/_missing_translations_it.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_ja.json b/app/assets/i18n/_missing_translations_ja.json index 5c2398a4633..ba792ab43a8 100644 --- a/app/assets/i18n/_missing_translations_ja.json +++ b/app/assets/i18n/_missing_translations_ja.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_km.json b/app/assets/i18n/_missing_translations_km.json index c18908ce4d8..b9ea99f2472 100644 --- a/app/assets/i18n/_missing_translations_km.json +++ b/app/assets/i18n/_missing_translations_km.json @@ -21,6 +21,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_ko.json b/app/assets/i18n/_missing_translations_ko.json index a23c5f94e24..dd9dac2e151 100644 --- a/app/assets/i18n/_missing_translations_ko.json +++ b/app/assets/i18n/_missing_translations_ko.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_ne.json b/app/assets/i18n/_missing_translations_ne.json index cc954088362..7c5e9ac4995 100644 --- a/app/assets/i18n/_missing_translations_ne.json +++ b/app/assets/i18n/_missing_translations_ne.json @@ -26,6 +26,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_nl.json b/app/assets/i18n/_missing_translations_nl.json index ef501965f49..ae21f672ef2 100644 --- a/app/assets/i18n/_missing_translations_nl.json +++ b/app/assets/i18n/_missing_translations_nl.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_pl.json b/app/assets/i18n/_missing_translations_pl.json index 16ede6c70f5..a723ebf979a 100644 --- a/app/assets/i18n/_missing_translations_pl.json +++ b/app/assets/i18n/_missing_translations_pl.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_pt_BR.json b/app/assets/i18n/_missing_translations_pt_BR.json index b685046d346..36ca323b4d8 100644 --- a/app/assets/i18n/_missing_translations_pt_BR.json +++ b/app/assets/i18n/_missing_translations_pt_BR.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_ru.json b/app/assets/i18n/_missing_translations_ru.json index 62fc9918e57..2261a77390c 100644 --- a/app/assets/i18n/_missing_translations_ru.json +++ b/app/assets/i18n/_missing_translations_ru.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_sv.json b/app/assets/i18n/_missing_translations_sv.json index 97c3c826c53..12daf72e3f2 100644 --- a/app/assets/i18n/_missing_translations_sv.json +++ b/app/assets/i18n/_missing_translations_sv.json @@ -26,6 +26,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_th.json b/app/assets/i18n/_missing_translations_th.json index 617e619a72d..676e7a04823 100644 --- a/app/assets/i18n/_missing_translations_th.json +++ b/app/assets/i18n/_missing_translations_th.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_tr.json b/app/assets/i18n/_missing_translations_tr.json index 1a08f34b556..37ed1674292 100644 --- a/app/assets/i18n/_missing_translations_tr.json +++ b/app/assets/i18n/_missing_translations_tr.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_uk.json b/app/assets/i18n/_missing_translations_uk.json index b6487ec1d24..a465bd8e1d5 100644 --- a/app/assets/i18n/_missing_translations_uk.json +++ b/app/assets/i18n/_missing_translations_uk.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_ur.json b/app/assets/i18n/_missing_translations_ur.json index 74ff5694dd4..82d42a2ea33 100644 --- a/app/assets/i18n/_missing_translations_ur.json +++ b/app/assets/i18n/_missing_translations_ur.json @@ -26,6 +26,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_vi.json b/app/assets/i18n/_missing_translations_vi.json index f72418e4acc..769ba18c18b 100644 --- a/app/assets/i18n/_missing_translations_vi.json +++ b/app/assets/i18n/_missing_translations_vi.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_zh_CN.json b/app/assets/i18n/_missing_translations_zh_CN.json index 5f78e1e7f25..16552af67be 100644 --- a/app/assets/i18n/_missing_translations_zh_CN.json +++ b/app/assets/i18n/_missing_translations_zh_CN.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_zh_HK.json b/app/assets/i18n/_missing_translations_zh_HK.json index 88bdc1d7ae6..699ea7fcdf5 100644 --- a/app/assets/i18n/_missing_translations_zh_HK.json +++ b/app/assets/i18n/_missing_translations_zh_HK.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/_missing_translations_zh_TW.json b/app/assets/i18n/_missing_translations_zh_TW.json index e92f138642f..b0479c09600 100644 --- a/app/assets/i18n/_missing_translations_zh_TW.json +++ b/app/assets/i18n/_missing_translations_zh_TW.json @@ -12,6 +12,15 @@ "termsOfUse": "Terms of Use" } }, + "aboutPage": { + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" + }, "donationPage": { "title": "Donate", "info": "LocalSend is free, open source and without any ads. If you like the app, you can support the development with a donation.", diff --git a/app/assets/i18n/strings.i18n.json b/app/assets/i18n/strings.i18n.json index 50e650cc00f..1056e4f0d73 100644 --- a/app/assets/i18n/strings.i18n.json +++ b/app/assets/i18n/strings.i18n.json @@ -220,7 +220,14 @@ "pendingRequests": "Pending requests: {n}" }, "aboutPage": { - "title": "About LocalSend" + "title": "About LocalSend", + "description": [ + "LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.", + "This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage." + ], + "author": "Author", + "contributors": "Contributors", + "translators": "Translators" }, "donationPage": { "title": "Donate", diff --git a/app/assets/i18n/strings_de.i18n.json b/app/assets/i18n/strings_de.i18n.json index a2b667e67e9..39b42a410b7 100644 --- a/app/assets/i18n/strings_de.i18n.json +++ b/app/assets/i18n/strings_de.i18n.json @@ -220,7 +220,14 @@ "pendingRequests": "Offene Anfragen: {n}" }, "aboutPage": { - "title": "Über LocalSend" + "title": "Über LocalSend", + "description": [ + "LocalSend ist eine kostenlose Open-Source-App, mit der du Dateien und Nachrichten sicher über dein lokales Netzwerk mit Geräten in der Nähe teilen kannst, ohne dass eine Internetverbindung erforderlich ist.", + "Diese App ist für Android, iOS, macOS, Windows und Linux verfügbar. Alle Downloadmöglichkeiten findest du auf der offiziellen Homepage." + ], + "author": "Autor", + "contributors": "Mitwirkende", + "translators": "Übersetzer:innen" }, "donationPage": { "title": "Spenden", diff --git a/app/lib/gen/strings.g.dart b/app/lib/gen/strings.g.dart index d26b76480cc..ec5e5e838aa 100644 --- a/app/lib/gen/strings.g.dart +++ b/app/lib/gen/strings.g.dart @@ -4,7 +4,7 @@ /// To regenerate, run: `dart run slang` /// /// Locales: 33 -/// Strings: 8932 (270 per locale) +/// Strings: 8942 (270 per locale) // coverage:ignore-file diff --git a/app/lib/gen/strings_de.g.dart b/app/lib/gen/strings_de.g.dart index 4e4bd081e90..dd8d3922aa6 100644 --- a/app/lib/gen/strings_de.g.dart +++ b/app/lib/gen/strings_de.g.dart @@ -276,6 +276,13 @@ class _StringsAboutPageDe extends _StringsAboutPageEn { // Translations @override String get title => 'Über LocalSend'; + @override List get description => [ + 'LocalSend ist eine kostenlose Open-Source-App, mit der du Dateien und Nachrichten sicher über dein lokales Netzwerk mit Geräten in der Nähe teilen kannst, ohne dass eine Internetverbindung erforderlich ist.', + 'Diese App ist für Android, iOS, macOS, Windows und Linux verfügbar. Alle Downloadmöglichkeiten findest du auf der offiziellen Homepage.', + ]; + @override String get author => 'Autor'; + @override String get contributors => 'Mitwirkende'; + @override String get translators => 'Übersetzer:innen'; } // Path: donationPage diff --git a/app/lib/gen/strings_en.g.dart b/app/lib/gen/strings_en.g.dart index cfd6bb2f699..c46abf45100 100644 --- a/app/lib/gen/strings_en.g.dart +++ b/app/lib/gen/strings_en.g.dart @@ -275,6 +275,13 @@ class _StringsAboutPageEn { // Translations String get title => 'About LocalSend'; + List get description => [ + 'LocalSend is a free, open-source app that allows you to securely share files and messages with nearby devices over your local network without needing an internet connection.', + 'This app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage.', + ]; + String get author => 'Author'; + String get contributors => 'Contributors'; + String get translators => 'Translators'; } // Path: donationPage diff --git a/app/lib/pages/about_page.dart b/app/lib/pages/about/about_page.dart similarity index 67% rename from app/lib/pages/about_page.dart rename to app/lib/pages/about/about_page.dart index bd9da02671f..b7946699b9c 100644 --- a/app/lib/pages/about_page.dart +++ b/app/lib/pages/about/about_page.dart @@ -6,20 +6,9 @@ import 'package:localsend_app/widget/responsive_list_view.dart'; import 'package:routerino/routerino.dart'; import 'package:url_launcher/url_launcher.dart'; -final _body = ''' - LocalSend is an open source app to share files and messages between nearby devices using the local wifi network. - The communication between devices is entirely end-to-end encrypted via HTTPS. - No Internet required. No tracking*. No ads. - - Currently, this app is available on Android, iOS, macOS, Windows and Linux. You can find all download options on the official homepage. +part 'contributors.dart'; - *The operating system may still gather usage data. - ''' - .splitMapJoin( - RegExp(r'^', multiLine: true), - onMatch: (_) => '\n', - onNonMatch: (n) => n.trim(), -); +part 'translators.dart'; class AboutPage extends StatelessWidget { const AboutPage(); @@ -48,7 +37,35 @@ class AboutPage extends StatelessWidget { child: const Text('localsend.org'), ), ), - Text(_body), + Text(t.aboutPage.description.join('\n\n')), + const SizedBox(height: 20), + Text(t.aboutPage.author, style: const TextStyle(fontWeight: FontWeight.bold)), + const Text('Tien Do Nam (@Tienisto)'), + const SizedBox(height: 20), + Text(t.aboutPage.contributors, style: const TextStyle(fontWeight: FontWeight.bold)), + ..._contributors.map((e) => Text(e)), + const SizedBox(height: 20), + Text(t.aboutPage.translators, style: const TextStyle(fontWeight: FontWeight.bold)), + Table( + columnWidths: const { + 0: IntrinsicColumnWidth(), + 1: FlexColumnWidth(), + }, + children: [ + ..._translators.entries.map( + (e) => TableRow( + children: [ + Padding( + padding: const EdgeInsets.only(right: 10), + child: Text(e.key.translations.locale), + ), + Text(e.value.join('\n')), + ], + ), + ), + ], + ), + const SizedBox(height: 10), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/app/lib/pages/about/contributors.dart b/app/lib/pages/about/contributors.dart new file mode 100644 index 00000000000..d039515753f --- /dev/null +++ b/app/lib/pages/about/contributors.dart @@ -0,0 +1,7 @@ +part of 'about_page.dart'; + +/// Contributors who made several contributions to the project. +/// Translators should not be listed here. +const _contributors = [ + 'Gabriel Lima (@TheGB0077)' +]; diff --git a/app/lib/pages/about/translators.dart b/app/lib/pages/about/translators.dart new file mode 100644 index 00000000000..8bcd9c97f7e --- /dev/null +++ b/app/lib/pages/about/translators.dart @@ -0,0 +1,29 @@ +part of 'about_page.dart'; + +/// Translators who translated the app to a specific language. +/// The list might be incomplete. +/// Also write your full name here if you want. +const _translators = >{ + AppLocale.ar: ['@Adam1141'], + AppLocale.bn: ['@RishiASheth'], + AppLocale.cs: ['@Amereyeu'], + AppLocale.de: ['Tien Do Nam (@Tienisto)'], + AppLocale.el: ['Petros Kyladitis (@multipetros)'], + AppLocale.en: ['Tien Do Nam (@Tienisto)'], + AppLocale.esEs: ['Esteban Daniel Saracho (@esaracho)'], + AppLocale.fa: ['@farshad991'], + AppLocale.frFr: ['@Nixuge'], + AppLocale.he: ['@ShlomoCode'], + AppLocale.hu: ['@gidano'], + AppLocale.it: ['@Francesco146'], + AppLocale.ja: ['soya_daizu (@soya-daizu)'], + AppLocale.km: ['Chandara H. Wei (@nidexingg)'], + AppLocale.ko: ['@mgmix'], + AppLocale.ptBr: ['Gabriel Lima (@TheGB0077)'], + AppLocale.ru: ['Sergiy (@sergd88)'], + AppLocale.uk: ['Sergiy (@sergd88)'], + AppLocale.vi: ['@faea726'], + AppLocale.zhCn: ['@nkh0472', '@graphemecluster'], + AppLocale.zhHk: ['@graphemecluster'], + AppLocale.zhTw: ['@Neo1102', '@graphemecluster'], +}; diff --git a/app/lib/pages/tabs/settings_tab.dart b/app/lib/pages/tabs/settings_tab.dart index 493c35834c6..40478b75c4f 100644 --- a/app/lib/pages/tabs/settings_tab.dart +++ b/app/lib/pages/tabs/settings_tab.dart @@ -3,7 +3,7 @@ import 'package:localsend_app/constants.dart'; import 'package:localsend_app/gen/strings.g.dart'; import 'package:localsend_app/model/device.dart'; import 'package:localsend_app/model/persistence/color_mode.dart'; -import 'package:localsend_app/pages/about_page.dart'; +import 'package:localsend_app/pages/about/about_page.dart'; import 'package:localsend_app/pages/changelog_page.dart'; import 'package:localsend_app/pages/donation/donation_page.dart'; import 'package:localsend_app/pages/language_page.dart'; From 7ff43c5a10d3e54cdc9c6e1e0b1b28132b90072e Mon Sep 17 00:00:00 2001 From: Tien Do Nam Date: Sun, 19 Nov 2023 01:06:13 +0100 Subject: [PATCH 28/31] i18n: simplify fr-FR to fr --- ..._FR.json => _missing_translations_fr.json} | 4 +- app/assets/i18n/_unused_translations.json | 2 +- ...s_fr-FR.i18n.json => strings_fr.i18n.json} | 2 +- app/ios/Runner/Info.plist | 2 +- app/lib/gen/strings.g.dart | 4 +- ...strings_fr_FR.g.dart => strings_fr.g.dart} | 466 +++++++++--------- app/lib/pages/about/translators.dart | 2 +- app/macos/Runner/Info.plist | 2 +- app/pubspec.yaml | 2 +- 9 files changed, 243 insertions(+), 243 deletions(-) rename app/assets/i18n/{_missing_translations_fr_FR.json => _missing_translations_fr.json} (88%) rename app/assets/i18n/{strings_fr-FR.i18n.json => strings_fr.i18n.json} (99%) rename app/lib/gen/{strings_fr_FR.g.dart => strings_fr.g.dart} (53%) diff --git a/app/assets/i18n/_missing_translations_fr_FR.json b/app/assets/i18n/_missing_translations_fr.json similarity index 88% rename from app/assets/i18n/_missing_translations_fr_FR.json rename to app/assets/i18n/_missing_translations_fr.json index a00873560fb..2975fc5af90 100644 --- a/app/assets/i18n/_missing_translations_fr_FR.json +++ b/app/assets/i18n/_missing_translations_fr.json @@ -1,7 +1,7 @@ { "@@info": [ - "Here are translations that exist in but not in .", - "After editing this file, you can run 'dart run slang apply --locale=fr-FR' to quickly apply the newly added translations." + "Here are translations that exist in but not in .", + "After editing this file, you can run 'dart run slang apply --locale=fr' to quickly apply the newly added translations." ], "settingsTab": { "other": { diff --git a/app/assets/i18n/_unused_translations.json b/app/assets/i18n/_unused_translations.json index 6587186e673..47af372a773 100644 --- a/app/assets/i18n/_unused_translations.json +++ b/app/assets/i18n/_unused_translations.json @@ -28,7 +28,7 @@ "eu": {}, "fa": {}, "fil-PH": {}, - "fr-FR": {}, + "fr": {}, "he": {}, "hu": {}, "id": {}, diff --git a/app/assets/i18n/strings_fr-FR.i18n.json b/app/assets/i18n/strings_fr.i18n.json similarity index 99% rename from app/assets/i18n/strings_fr-FR.i18n.json rename to app/assets/i18n/strings_fr.i18n.json index 3333cafda6f..3984612821b 100644 --- a/app/assets/i18n/strings_fr-FR.i18n.json +++ b/app/assets/i18n/strings_fr.i18n.json @@ -1,5 +1,5 @@ { - "locale": "Français (France)", + "locale": "Français", "appName": "LocalSend", "general": { "accept": "Accepter", diff --git a/app/ios/Runner/Info.plist b/app/ios/Runner/Info.plist index 9454d8350b9..577a8269591 100644 --- a/app/ios/Runner/Info.plist +++ b/app/ios/Runner/Info.plist @@ -63,7 +63,7 @@ es-ES eu fa - fr-FR + fr he hu id diff --git a/app/lib/gen/strings.g.dart b/app/lib/gen/strings.g.dart index ec5e5e838aa..3581e7391e8 100644 --- a/app/lib/gen/strings.g.dart +++ b/app/lib/gen/strings.g.dart @@ -26,7 +26,7 @@ part 'strings_es_ES.g.dart'; part 'strings_eu.g.dart'; part 'strings_fa.g.dart'; part 'strings_fil_PH.g.dart'; -part 'strings_fr_FR.g.dart'; +part 'strings_fr.g.dart'; part 'strings_he.g.dart'; part 'strings_hu.g.dart'; part 'strings_id.g.dart'; @@ -69,7 +69,7 @@ enum AppLocale with BaseAppLocale { eu(languageCode: 'eu', build: _StringsEu.build), fa(languageCode: 'fa', build: _StringsFa.build), filPh(languageCode: 'fil', countryCode: 'PH', build: _StringsFilPh.build), - frFr(languageCode: 'fr', countryCode: 'FR', build: _StringsFrFr.build), + fr(languageCode: 'fr', build: _StringsFr.build), he(languageCode: 'he', build: _StringsHe.build), hu(languageCode: 'hu', build: _StringsHu.build), id(languageCode: 'id', build: _StringsId.build), diff --git a/app/lib/gen/strings_fr_FR.g.dart b/app/lib/gen/strings_fr.g.dart similarity index 53% rename from app/lib/gen/strings_fr_FR.g.dart rename to app/lib/gen/strings_fr.g.dart index 9bcfa5d7e1f..c2bd45815d8 100644 --- a/app/lib/gen/strings_fr_FR.g.dart +++ b/app/lib/gen/strings_fr.g.dart @@ -1,55 +1,55 @@ part of 'strings.g.dart'; // Path: -class _StringsFrFr extends _StringsEn { +class _StringsFr extends _StringsEn { /// You can call this constructor and build your own translation instance of this locale. /// Constructing via the enum [AppLocale.build] is preferred. - _StringsFrFr.build({Map? overrides, PluralResolver? cardinalResolver, PluralResolver? ordinalResolver}) + _StringsFr.build({Map? overrides, PluralResolver? cardinalResolver, PluralResolver? ordinalResolver}) : assert(overrides == null, 'Set "translation_overrides: true" in order to enable this feature.'), $meta = TranslationMetadata( - locale: AppLocale.frFr, + locale: AppLocale.fr, overrides: overrides ?? {}, cardinalResolver: cardinalResolver, ordinalResolver: ordinalResolver, ), super.build(cardinalResolver: cardinalResolver, ordinalResolver: ordinalResolver); - /// Metadata for the translations of . + /// Metadata for the translations of . @override final TranslationMetadata $meta; - @override late final _StringsFrFr _root = this; // ignore: unused_field + @override late final _StringsFr _root = this; // ignore: unused_field // Translations - @override String get locale => 'Français (France)'; + @override String get locale => 'Français'; @override String get appName => 'LocalSend'; - @override late final _StringsGeneralFrFr general = _StringsGeneralFrFr._(_root); - @override late final _StringsReceiveTabFrFr receiveTab = _StringsReceiveTabFrFr._(_root); - @override late final _StringsSendTabFrFr sendTab = _StringsSendTabFrFr._(_root); - @override late final _StringsSettingsTabFrFr settingsTab = _StringsSettingsTabFrFr._(_root); - @override late final _StringsTroubleshootPageFrFr troubleshootPage = _StringsTroubleshootPageFrFr._(_root); - @override late final _StringsReceiveHistoryPageFrFr receiveHistoryPage = _StringsReceiveHistoryPageFrFr._(_root); - @override late final _StringsApkPickerPageFrFr apkPickerPage = _StringsApkPickerPageFrFr._(_root); - @override late final _StringsSelectedFilesPageFrFr selectedFilesPage = _StringsSelectedFilesPageFrFr._(_root); - @override late final _StringsReceivePageFrFr receivePage = _StringsReceivePageFrFr._(_root); - @override late final _StringsReceiveOptionsPageFrFr receiveOptionsPage = _StringsReceiveOptionsPageFrFr._(_root); - @override late final _StringsSendPageFrFr sendPage = _StringsSendPageFrFr._(_root); - @override late final _StringsProgressPageFrFr progressPage = _StringsProgressPageFrFr._(_root); - @override late final _StringsWebSharePageFrFr webSharePage = _StringsWebSharePageFrFr._(_root); - @override late final _StringsAboutPageFrFr aboutPage = _StringsAboutPageFrFr._(_root); - @override late final _StringsChangelogPageFrFr changelogPage = _StringsChangelogPageFrFr._(_root); - @override late final _StringsAliasGeneratorFrFr aliasGenerator = _StringsAliasGeneratorFrFr._(_root); - @override late final _StringsDialogsFrFr dialogs = _StringsDialogsFrFr._(_root); - @override late final _StringsTrayFrFr tray = _StringsTrayFrFr._(_root); - @override late final _StringsWebFrFr web = _StringsWebFrFr._(_root); - @override late final _StringsAssetPickerFrFr assetPicker = _StringsAssetPickerFrFr._(_root); + @override late final _StringsGeneralFr general = _StringsGeneralFr._(_root); + @override late final _StringsReceiveTabFr receiveTab = _StringsReceiveTabFr._(_root); + @override late final _StringsSendTabFr sendTab = _StringsSendTabFr._(_root); + @override late final _StringsSettingsTabFr settingsTab = _StringsSettingsTabFr._(_root); + @override late final _StringsTroubleshootPageFr troubleshootPage = _StringsTroubleshootPageFr._(_root); + @override late final _StringsReceiveHistoryPageFr receiveHistoryPage = _StringsReceiveHistoryPageFr._(_root); + @override late final _StringsApkPickerPageFr apkPickerPage = _StringsApkPickerPageFr._(_root); + @override late final _StringsSelectedFilesPageFr selectedFilesPage = _StringsSelectedFilesPageFr._(_root); + @override late final _StringsReceivePageFr receivePage = _StringsReceivePageFr._(_root); + @override late final _StringsReceiveOptionsPageFr receiveOptionsPage = _StringsReceiveOptionsPageFr._(_root); + @override late final _StringsSendPageFr sendPage = _StringsSendPageFr._(_root); + @override late final _StringsProgressPageFr progressPage = _StringsProgressPageFr._(_root); + @override late final _StringsWebSharePageFr webSharePage = _StringsWebSharePageFr._(_root); + @override late final _StringsAboutPageFr aboutPage = _StringsAboutPageFr._(_root); + @override late final _StringsChangelogPageFr changelogPage = _StringsChangelogPageFr._(_root); + @override late final _StringsAliasGeneratorFr aliasGenerator = _StringsAliasGeneratorFr._(_root); + @override late final _StringsDialogsFr dialogs = _StringsDialogsFr._(_root); + @override late final _StringsTrayFr tray = _StringsTrayFr._(_root); + @override late final _StringsWebFr web = _StringsWebFr._(_root); + @override late final _StringsAssetPickerFr assetPicker = _StringsAssetPickerFr._(_root); } // Path: general -class _StringsGeneralFrFr extends _StringsGeneralEn { - _StringsGeneralFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsGeneralFr extends _StringsGeneralEn { + _StringsGeneralFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get accept => 'Accepter'; @@ -92,85 +92,85 @@ class _StringsGeneralFrFr extends _StringsGeneralEn { } // Path: receiveTab -class _StringsReceiveTabFrFr extends _StringsReceiveTabEn { - _StringsReceiveTabFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsReceiveTabFr extends _StringsReceiveTabEn { + _StringsReceiveTabFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Recevoir'; - @override late final _StringsReceiveTabInfoBoxFrFr infoBox = _StringsReceiveTabInfoBoxFrFr._(_root); + @override late final _StringsReceiveTabInfoBoxFr infoBox = _StringsReceiveTabInfoBoxFr._(_root); } // Path: sendTab -class _StringsSendTabFrFr extends _StringsSendTabEn { - _StringsSendTabFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsSendTabFr extends _StringsSendTabEn { + _StringsSendTabFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Envoyer'; - @override late final _StringsSendTabSelectionFrFr selection = _StringsSendTabSelectionFrFr._(_root); - @override late final _StringsSendTabPickerFrFr picker = _StringsSendTabPickerFrFr._(_root); + @override late final _StringsSendTabSelectionFr selection = _StringsSendTabSelectionFr._(_root); + @override late final _StringsSendTabPickerFr picker = _StringsSendTabPickerFr._(_root); @override String get shareIntentInfo => 'Vous pouvez également utiliser la fonction "Partager" de votre appareil pour sélectionner des fichiers plus facilement.'; @override String get nearbyDevices => 'Appareils à proximité'; @override String get thisDevice => 'Cet Appareil'; @override String get scan => 'Recherchez des appareils'; @override String get sendMode => 'Mode envoi'; - @override late final _StringsSendTabSendModesFrFr sendModes = _StringsSendTabSendModesFrFr._(_root); + @override late final _StringsSendTabSendModesFr sendModes = _StringsSendTabSendModesFr._(_root); @override String get sendModeHelp => 'Explication'; @override String get help => 'Veuillez vous assurer que la cible souhaitée se trouve également dans le même réseau wifi.'; @override String get placeItems => 'Placez des éléments à partager.'; } // Path: settingsTab -class _StringsSettingsTabFrFr extends _StringsSettingsTabEn { - _StringsSettingsTabFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsSettingsTabFr extends _StringsSettingsTabEn { + _StringsSettingsTabFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Paramètres'; - @override late final _StringsSettingsTabGeneralFrFr general = _StringsSettingsTabGeneralFrFr._(_root); - @override late final _StringsSettingsTabReceiveFrFr receive = _StringsSettingsTabReceiveFrFr._(_root); - @override late final _StringsSettingsTabNetworkFrFr network = _StringsSettingsTabNetworkFrFr._(_root); + @override late final _StringsSettingsTabGeneralFr general = _StringsSettingsTabGeneralFr._(_root); + @override late final _StringsSettingsTabReceiveFr receive = _StringsSettingsTabReceiveFr._(_root); + @override late final _StringsSettingsTabNetworkFr network = _StringsSettingsTabNetworkFr._(_root); @override String get advancedSettings => 'Paramètres avancés'; } // Path: troubleshootPage -class _StringsTroubleshootPageFrFr extends _StringsTroubleshootPageEn { - _StringsTroubleshootPageFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsTroubleshootPageFr extends _StringsTroubleshootPageEn { + _StringsTroubleshootPageFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Dépannage'; @override String get subTitle => 'Cette application ne marche pas comme vous l\'espérez? Vous pouvez ici trouver des solutions à des problèmes communs.'; @override String get solution => 'Solution:'; @override String get fixButton => 'Régler automatiquement'; - @override late final _StringsTroubleshootPageFirewallFrFr firewall = _StringsTroubleshootPageFirewallFrFr._(_root); - @override late final _StringsTroubleshootPageNoConnectionFrFr noConnection = _StringsTroubleshootPageNoConnectionFrFr._(_root); + @override late final _StringsTroubleshootPageFirewallFr firewall = _StringsTroubleshootPageFirewallFr._(_root); + @override late final _StringsTroubleshootPageNoConnectionFr noConnection = _StringsTroubleshootPageNoConnectionFr._(_root); } // Path: receiveHistoryPage -class _StringsReceiveHistoryPageFrFr extends _StringsReceiveHistoryPageEn { - _StringsReceiveHistoryPageFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsReceiveHistoryPageFr extends _StringsReceiveHistoryPageEn { + _StringsReceiveHistoryPageFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Historique'; @override String get openFolder => 'Ouvrir le dossier'; @override String get deleteHistory => 'Supprimer l\'historique'; @override String get empty => 'L\'historique est vide.'; - @override late final _StringsReceiveHistoryPageEntryActionsFrFr entryActions = _StringsReceiveHistoryPageEntryActionsFrFr._(_root); + @override late final _StringsReceiveHistoryPageEntryActionsFr entryActions = _StringsReceiveHistoryPageEntryActionsFr._(_root); } // Path: apkPickerPage -class _StringsApkPickerPageFrFr extends _StringsApkPickerPageEn { - _StringsApkPickerPageFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsApkPickerPageFr extends _StringsApkPickerPageEn { + _StringsApkPickerPageFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Application (APK)'; @@ -180,20 +180,20 @@ class _StringsApkPickerPageFrFr extends _StringsApkPickerPageEn { } // Path: selectedFilesPage -class _StringsSelectedFilesPageFrFr extends _StringsSelectedFilesPageEn { - _StringsSelectedFilesPageFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsSelectedFilesPageFr extends _StringsSelectedFilesPageEn { + _StringsSelectedFilesPageFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get deleteAll => 'Tout supprimer'; } // Path: receivePage -class _StringsReceivePageFrFr extends _StringsReceivePageEn { - _StringsReceivePageFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsReceivePageFr extends _StringsReceivePageEn { + _StringsReceivePageFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String subTitle({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('fr'))(n, @@ -206,10 +206,10 @@ class _StringsReceivePageFrFr extends _StringsReceivePageEn { } // Path: receiveOptionsPage -class _StringsReceiveOptionsPageFrFr extends _StringsReceiveOptionsPageEn { - _StringsReceiveOptionsPageFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsReceiveOptionsPageFr extends _StringsReceiveOptionsPageEn { + _StringsReceiveOptionsPageFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Options'; @@ -220,10 +220,10 @@ class _StringsReceiveOptionsPageFrFr extends _StringsReceiveOptionsPageEn { } // Path: sendPage -class _StringsSendPageFrFr extends _StringsSendPageEn { - _StringsSendPageFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsSendPageFr extends _StringsSendPageEn { + _StringsSendPageFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get waiting => 'En attente d\'une réponse...'; @@ -232,23 +232,23 @@ class _StringsSendPageFrFr extends _StringsSendPageEn { } // Path: progressPage -class _StringsProgressPageFrFr extends _StringsProgressPageEn { - _StringsProgressPageFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsProgressPageFr extends _StringsProgressPageEn { + _StringsProgressPageFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get titleSending => 'Envoi de fichiers'; @override String get titleReceiving => 'Réception des fichiers'; @override String get savedToGallery => 'Sauvegardé dans Photos'; - @override late final _StringsProgressPageTotalFrFr total = _StringsProgressPageTotalFrFr._(_root); + @override late final _StringsProgressPageTotalFr total = _StringsProgressPageTotalFr._(_root); } // Path: webSharePage -class _StringsWebSharePageFrFr extends _StringsWebSharePageEn { - _StringsWebSharePageFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsWebSharePageFr extends _StringsWebSharePageEn { + _StringsWebSharePageFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Partager via un lien'; @@ -267,69 +267,69 @@ class _StringsWebSharePageFrFr extends _StringsWebSharePageEn { } // Path: aboutPage -class _StringsAboutPageFrFr extends _StringsAboutPageEn { - _StringsAboutPageFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsAboutPageFr extends _StringsAboutPageEn { + _StringsAboutPageFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'A propos de LocalSend'; } // Path: changelogPage -class _StringsChangelogPageFrFr extends _StringsChangelogPageEn { - _StringsChangelogPageFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsChangelogPageFr extends _StringsChangelogPageEn { + _StringsChangelogPageFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Historique des mises à jour'; } // Path: aliasGenerator -class _StringsAliasGeneratorFrFr extends _StringsAliasGeneratorEn { - _StringsAliasGeneratorFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsAliasGeneratorFr extends _StringsAliasGeneratorEn { + _StringsAliasGeneratorFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations } // Path: dialogs -class _StringsDialogsFrFr extends _StringsDialogsEn { - _StringsDialogsFrFr._(_StringsFrFr root) : this._root = root, super._(root); - - @override final _StringsFrFr _root; // ignore: unused_field - - // Translations - @override late final _StringsDialogsAddFileFrFr addFile = _StringsDialogsAddFileFrFr._(_root); - @override late final _StringsDialogsAddressInputFrFr addressInput = _StringsDialogsAddressInputFrFr._(_root); - @override late final _StringsDialogsCancelSessionFrFr cancelSession = _StringsDialogsCancelSessionFrFr._(_root); - @override late final _StringsDialogsCannotOpenFileFrFr cannotOpenFile = _StringsDialogsCannotOpenFileFrFr._(_root); - @override late final _StringsDialogsEncryptionDisabledNoticeFrFr encryptionDisabledNotice = _StringsDialogsEncryptionDisabledNoticeFrFr._(_root); - @override late final _StringsDialogsErrorDialogFrFr errorDialog = _StringsDialogsErrorDialogFrFr._(_root); - @override late final _StringsDialogsFavoriteDialogFrFr favoriteDialog = _StringsDialogsFavoriteDialogFrFr._(_root); - @override late final _StringsDialogsFavoriteDeleteDialogFrFr favoriteDeleteDialog = _StringsDialogsFavoriteDeleteDialogFrFr._(_root); - @override late final _StringsDialogsFavoriteEditDialogFrFr favoriteEditDialog = _StringsDialogsFavoriteEditDialogFrFr._(_root); - @override late final _StringsDialogsFileInfoFrFr fileInfo = _StringsDialogsFileInfoFrFr._(_root); - @override late final _StringsDialogsFileNameInputFrFr fileNameInput = _StringsDialogsFileNameInputFrFr._(_root); - @override late final _StringsDialogsHistoryClearDialogFrFr historyClearDialog = _StringsDialogsHistoryClearDialogFrFr._(_root); - @override late final _StringsDialogsLocalNetworkUnauthorizedFrFr localNetworkUnauthorized = _StringsDialogsLocalNetworkUnauthorizedFrFr._(_root); - @override late final _StringsDialogsMessageInputFrFr messageInput = _StringsDialogsMessageInputFrFr._(_root); - @override late final _StringsDialogsNoFilesFrFr noFiles = _StringsDialogsNoFilesFrFr._(_root); - @override late final _StringsDialogsNoPermissionFrFr noPermission = _StringsDialogsNoPermissionFrFr._(_root); - @override late final _StringsDialogsNotAvailableOnPlatformFrFr notAvailableOnPlatform = _StringsDialogsNotAvailableOnPlatformFrFr._(_root); - @override late final _StringsDialogsQrFrFr qr = _StringsDialogsQrFrFr._(_root); - @override late final _StringsDialogsQuickActionsFrFr quickActions = _StringsDialogsQuickActionsFrFr._(_root); - @override late final _StringsDialogsQuickSaveNoticeFrFr quickSaveNotice = _StringsDialogsQuickSaveNoticeFrFr._(_root); - @override late final _StringsDialogsSendModeHelpFrFr sendModeHelp = _StringsDialogsSendModeHelpFrFr._(_root); +class _StringsDialogsFr extends _StringsDialogsEn { + _StringsDialogsFr._(_StringsFr root) : this._root = root, super._(root); + + @override final _StringsFr _root; // ignore: unused_field + + // Translations + @override late final _StringsDialogsAddFileFr addFile = _StringsDialogsAddFileFr._(_root); + @override late final _StringsDialogsAddressInputFr addressInput = _StringsDialogsAddressInputFr._(_root); + @override late final _StringsDialogsCancelSessionFr cancelSession = _StringsDialogsCancelSessionFr._(_root); + @override late final _StringsDialogsCannotOpenFileFr cannotOpenFile = _StringsDialogsCannotOpenFileFr._(_root); + @override late final _StringsDialogsEncryptionDisabledNoticeFr encryptionDisabledNotice = _StringsDialogsEncryptionDisabledNoticeFr._(_root); + @override late final _StringsDialogsErrorDialogFr errorDialog = _StringsDialogsErrorDialogFr._(_root); + @override late final _StringsDialogsFavoriteDialogFr favoriteDialog = _StringsDialogsFavoriteDialogFr._(_root); + @override late final _StringsDialogsFavoriteDeleteDialogFr favoriteDeleteDialog = _StringsDialogsFavoriteDeleteDialogFr._(_root); + @override late final _StringsDialogsFavoriteEditDialogFr favoriteEditDialog = _StringsDialogsFavoriteEditDialogFr._(_root); + @override late final _StringsDialogsFileInfoFr fileInfo = _StringsDialogsFileInfoFr._(_root); + @override late final _StringsDialogsFileNameInputFr fileNameInput = _StringsDialogsFileNameInputFr._(_root); + @override late final _StringsDialogsHistoryClearDialogFr historyClearDialog = _StringsDialogsHistoryClearDialogFr._(_root); + @override late final _StringsDialogsLocalNetworkUnauthorizedFr localNetworkUnauthorized = _StringsDialogsLocalNetworkUnauthorizedFr._(_root); + @override late final _StringsDialogsMessageInputFr messageInput = _StringsDialogsMessageInputFr._(_root); + @override late final _StringsDialogsNoFilesFr noFiles = _StringsDialogsNoFilesFr._(_root); + @override late final _StringsDialogsNoPermissionFr noPermission = _StringsDialogsNoPermissionFr._(_root); + @override late final _StringsDialogsNotAvailableOnPlatformFr notAvailableOnPlatform = _StringsDialogsNotAvailableOnPlatformFr._(_root); + @override late final _StringsDialogsQrFr qr = _StringsDialogsQrFr._(_root); + @override late final _StringsDialogsQuickActionsFr quickActions = _StringsDialogsQuickActionsFr._(_root); + @override late final _StringsDialogsQuickSaveNoticeFr quickSaveNotice = _StringsDialogsQuickSaveNoticeFr._(_root); + @override late final _StringsDialogsSendModeHelpFr sendModeHelp = _StringsDialogsSendModeHelpFr._(_root); } // Path: tray -class _StringsTrayFrFr extends _StringsTrayEn { - _StringsTrayFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsTrayFr extends _StringsTrayEn { + _StringsTrayFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get open => '${_root.general.open}'; @@ -337,10 +337,10 @@ class _StringsTrayFrFr extends _StringsTrayEn { } // Path: web -class _StringsWebFrFr extends _StringsWebEn { - _StringsWebFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsWebFr extends _StringsWebEn { + _StringsWebFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get waiting => '${_root.sendPage.waiting}'; @@ -351,10 +351,10 @@ class _StringsWebFrFr extends _StringsWebEn { } // Path: assetPicker -class _StringsAssetPickerFrFr extends _StringsAssetPickerEn { - _StringsAssetPickerFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsAssetPickerFr extends _StringsAssetPickerEn { + _StringsAssetPickerFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get confirm => 'OK'; @@ -388,10 +388,10 @@ class _StringsAssetPickerFrFr extends _StringsAssetPickerEn { } // Path: receiveTab.infoBox -class _StringsReceiveTabInfoBoxFrFr extends _StringsReceiveTabInfoBoxEn { - _StringsReceiveTabInfoBoxFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsReceiveTabInfoBoxFr extends _StringsReceiveTabInfoBoxEn { + _StringsReceiveTabInfoBoxFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get ip => 'IP:'; @@ -400,10 +400,10 @@ class _StringsReceiveTabInfoBoxFrFr extends _StringsReceiveTabInfoBoxEn { } // Path: sendTab.selection -class _StringsSendTabSelectionFrFr extends _StringsSendTabSelectionEn { - _StringsSendTabSelectionFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsSendTabSelectionFr extends _StringsSendTabSelectionEn { + _StringsSendTabSelectionFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Sélection'; @@ -412,10 +412,10 @@ class _StringsSendTabSelectionFrFr extends _StringsSendTabSelectionEn { } // Path: sendTab.picker -class _StringsSendTabPickerFrFr extends _StringsSendTabPickerEn { - _StringsSendTabPickerFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsSendTabPickerFr extends _StringsSendTabPickerEn { + _StringsSendTabPickerFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get file => 'Fichier'; @@ -427,10 +427,10 @@ class _StringsSendTabPickerFrFr extends _StringsSendTabPickerEn { } // Path: sendTab.sendModes -class _StringsSendTabSendModesFrFr extends _StringsSendTabSendModesEn { - _StringsSendTabSendModesFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsSendTabSendModesFr extends _StringsSendTabSendModesEn { + _StringsSendTabSendModesFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get single => 'Récipient unique'; @@ -439,19 +439,19 @@ class _StringsSendTabSendModesFrFr extends _StringsSendTabSendModesEn { } // Path: settingsTab.general -class _StringsSettingsTabGeneralFrFr extends _StringsSettingsTabGeneralEn { - _StringsSettingsTabGeneralFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsSettingsTabGeneralFr extends _StringsSettingsTabGeneralEn { + _StringsSettingsTabGeneralFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Général'; @override String get brightness => 'Luminosité'; - @override late final _StringsSettingsTabGeneralBrightnessOptionsFrFr brightnessOptions = _StringsSettingsTabGeneralBrightnessOptionsFrFr._(_root); + @override late final _StringsSettingsTabGeneralBrightnessOptionsFr brightnessOptions = _StringsSettingsTabGeneralBrightnessOptionsFr._(_root); @override String get color => 'Couleur'; - @override late final _StringsSettingsTabGeneralColorOptionsFrFr colorOptions = _StringsSettingsTabGeneralColorOptionsFrFr._(_root); + @override late final _StringsSettingsTabGeneralColorOptionsFr colorOptions = _StringsSettingsTabGeneralColorOptionsFr._(_root); @override String get language => 'Langue'; - @override late final _StringsSettingsTabGeneralLanguageOptionsFrFr languageOptions = _StringsSettingsTabGeneralLanguageOptionsFrFr._(_root); + @override late final _StringsSettingsTabGeneralLanguageOptionsFr languageOptions = _StringsSettingsTabGeneralLanguageOptionsFr._(_root); @override String get saveWindowPlacement => 'Quitter: Sauvegarder l\'emplacement de la fenêtre'; @override String get minimizeToTray => 'Quitter : Réduire à la barre des tâches'; @override String get launchAtStartup => 'Démarrage automatique : Après la connexion'; @@ -460,10 +460,10 @@ class _StringsSettingsTabGeneralFrFr extends _StringsSettingsTabGeneralEn { } // Path: settingsTab.receive -class _StringsSettingsTabReceiveFrFr extends _StringsSettingsTabReceiveEn { - _StringsSettingsTabReceiveFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsSettingsTabReceiveFr extends _StringsSettingsTabReceiveEn { + _StringsSettingsTabReceiveFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Reçu'; @@ -475,10 +475,10 @@ class _StringsSettingsTabReceiveFrFr extends _StringsSettingsTabReceiveEn { } // Path: settingsTab.network -class _StringsSettingsTabNetworkFrFr extends _StringsSettingsTabNetworkEn { - _StringsSettingsTabNetworkFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsSettingsTabNetworkFr extends _StringsSettingsTabNetworkEn { + _StringsSettingsTabNetworkFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Réseau'; @@ -495,10 +495,10 @@ class _StringsSettingsTabNetworkFrFr extends _StringsSettingsTabNetworkEn { } // Path: troubleshootPage.firewall -class _StringsTroubleshootPageFirewallFrFr extends _StringsTroubleshootPageFirewallEn { - _StringsTroubleshootPageFirewallFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsTroubleshootPageFirewallFr extends _StringsTroubleshootPageFirewallEn { + _StringsTroubleshootPageFirewallFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get symptom => 'Cet appareil peut envoyer des fichiers à d\'autres appareils, mais d\'autres appareils ne peuvent pas en envoyer à cet appareil.'; @@ -507,10 +507,10 @@ class _StringsTroubleshootPageFirewallFrFr extends _StringsTroubleshootPageFirew } // Path: troubleshootPage.noConnection -class _StringsTroubleshootPageNoConnectionFrFr extends _StringsTroubleshootPageNoConnectionEn { - _StringsTroubleshootPageNoConnectionFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsTroubleshootPageNoConnectionFr extends _StringsTroubleshootPageNoConnectionEn { + _StringsTroubleshootPageNoConnectionFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get symptom => 'Les deux appareils ne peuvent ni se trouver, ni partager des fichiers.'; @@ -518,10 +518,10 @@ class _StringsTroubleshootPageNoConnectionFrFr extends _StringsTroubleshootPageN } // Path: receiveHistoryPage.entryActions -class _StringsReceiveHistoryPageEntryActionsFrFr extends _StringsReceiveHistoryPageEntryActionsEn { - _StringsReceiveHistoryPageEntryActionsFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsReceiveHistoryPageEntryActionsFr extends _StringsReceiveHistoryPageEntryActionsEn { + _StringsReceiveHistoryPageEntryActionsFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get open => 'Ouvrir le fichier'; @@ -530,23 +530,23 @@ class _StringsReceiveHistoryPageEntryActionsFrFr extends _StringsReceiveHistoryP } // Path: progressPage.total -class _StringsProgressPageTotalFrFr extends _StringsProgressPageTotalEn { - _StringsProgressPageTotalFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsProgressPageTotalFr extends _StringsProgressPageTotalEn { + _StringsProgressPageTotalFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations - @override late final _StringsProgressPageTotalTitleFrFr title = _StringsProgressPageTotalTitleFrFr._(_root); + @override late final _StringsProgressPageTotalTitleFr title = _StringsProgressPageTotalTitleFr._(_root); @override String count({required Object curr, required Object n}) => 'Fichiers: ${curr} / ${n}'; @override String size({required Object curr, required Object n}) => 'Taille: ${curr} / ${n}'; @override String speed({required Object speed}) => 'Vitesse: ${speed}/s'; } // Path: dialogs.addFile -class _StringsDialogsAddFileFrFr extends _StringsDialogsAddFileEn { - _StringsDialogsAddFileFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsDialogsAddFileFr extends _StringsDialogsAddFileEn { + _StringsDialogsAddFileFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Ajouter à la sélection'; @@ -554,10 +554,10 @@ class _StringsDialogsAddFileFrFr extends _StringsDialogsAddFileEn { } // Path: dialogs.addressInput -class _StringsDialogsAddressInputFrFr extends _StringsDialogsAddressInputEn { - _StringsDialogsAddressInputFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsDialogsAddressInputFr extends _StringsDialogsAddressInputEn { + _StringsDialogsAddressInputFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Entrez l\'adresse'; @@ -567,10 +567,10 @@ class _StringsDialogsAddressInputFrFr extends _StringsDialogsAddressInputEn { } // Path: dialogs.cancelSession -class _StringsDialogsCancelSessionFrFr extends _StringsDialogsCancelSessionEn { - _StringsDialogsCancelSessionFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsDialogsCancelSessionFr extends _StringsDialogsCancelSessionEn { + _StringsDialogsCancelSessionFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Annuler le transfert de fichiers'; @@ -578,10 +578,10 @@ class _StringsDialogsCancelSessionFrFr extends _StringsDialogsCancelSessionEn { } // Path: dialogs.cannotOpenFile -class _StringsDialogsCannotOpenFileFrFr extends _StringsDialogsCannotOpenFileEn { - _StringsDialogsCannotOpenFileFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsDialogsCannotOpenFileFr extends _StringsDialogsCannotOpenFileEn { + _StringsDialogsCannotOpenFileFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Ne peut pas ouvrir le fichier'; @@ -589,10 +589,10 @@ class _StringsDialogsCannotOpenFileFrFr extends _StringsDialogsCannotOpenFileEn } // Path: dialogs.encryptionDisabledNotice -class _StringsDialogsEncryptionDisabledNoticeFrFr extends _StringsDialogsEncryptionDisabledNoticeEn { - _StringsDialogsEncryptionDisabledNoticeFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsDialogsEncryptionDisabledNoticeFr extends _StringsDialogsEncryptionDisabledNoticeEn { + _StringsDialogsEncryptionDisabledNoticeFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Chiffrement désactivé'; @@ -600,20 +600,20 @@ class _StringsDialogsEncryptionDisabledNoticeFrFr extends _StringsDialogsEncrypt } // Path: dialogs.errorDialog -class _StringsDialogsErrorDialogFrFr extends _StringsDialogsErrorDialogEn { - _StringsDialogsErrorDialogFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsDialogsErrorDialogFr extends _StringsDialogsErrorDialogEn { + _StringsDialogsErrorDialogFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => '${_root.general.error}'; } // Path: dialogs.favoriteDialog -class _StringsDialogsFavoriteDialogFrFr extends _StringsDialogsFavoriteDialogEn { - _StringsDialogsFavoriteDialogFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsDialogsFavoriteDialogFr extends _StringsDialogsFavoriteDialogEn { + _StringsDialogsFavoriteDialogFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Favoris'; @@ -622,10 +622,10 @@ class _StringsDialogsFavoriteDialogFrFr extends _StringsDialogsFavoriteDialogEn } // Path: dialogs.favoriteDeleteDialog -class _StringsDialogsFavoriteDeleteDialogFrFr extends _StringsDialogsFavoriteDeleteDialogEn { - _StringsDialogsFavoriteDeleteDialogFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsDialogsFavoriteDeleteDialogFr extends _StringsDialogsFavoriteDeleteDialogEn { + _StringsDialogsFavoriteDeleteDialogFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Supprimer des favoris'; @@ -633,10 +633,10 @@ class _StringsDialogsFavoriteDeleteDialogFrFr extends _StringsDialogsFavoriteDel } // Path: dialogs.favoriteEditDialog -class _StringsDialogsFavoriteEditDialogFrFr extends _StringsDialogsFavoriteEditDialogEn { - _StringsDialogsFavoriteEditDialogFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsDialogsFavoriteEditDialogFr extends _StringsDialogsFavoriteEditDialogEn { + _StringsDialogsFavoriteEditDialogFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get titleAdd => 'Ajouter aux favoris'; @@ -648,10 +648,10 @@ class _StringsDialogsFavoriteEditDialogFrFr extends _StringsDialogsFavoriteEditD } // Path: dialogs.fileInfo -class _StringsDialogsFileInfoFrFr extends _StringsDialogsFileInfoEn { - _StringsDialogsFileInfoFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsDialogsFileInfoFr extends _StringsDialogsFileInfoEn { + _StringsDialogsFileInfoFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Informations sur le fichier'; @@ -663,10 +663,10 @@ class _StringsDialogsFileInfoFrFr extends _StringsDialogsFileInfoEn { } // Path: dialogs.fileNameInput -class _StringsDialogsFileNameInputFrFr extends _StringsDialogsFileNameInputEn { - _StringsDialogsFileNameInputFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsDialogsFileNameInputFr extends _StringsDialogsFileNameInputEn { + _StringsDialogsFileNameInputFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Entrez le nom du fichier'; @@ -674,10 +674,10 @@ class _StringsDialogsFileNameInputFrFr extends _StringsDialogsFileNameInputEn { } // Path: dialogs.historyClearDialog -class _StringsDialogsHistoryClearDialogFrFr extends _StringsDialogsHistoryClearDialogEn { - _StringsDialogsHistoryClearDialogFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsDialogsHistoryClearDialogFr extends _StringsDialogsHistoryClearDialogEn { + _StringsDialogsHistoryClearDialogFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Effacer l\'historique'; @@ -685,10 +685,10 @@ class _StringsDialogsHistoryClearDialogFrFr extends _StringsDialogsHistoryClearD } // Path: dialogs.localNetworkUnauthorized -class _StringsDialogsLocalNetworkUnauthorizedFrFr extends _StringsDialogsLocalNetworkUnauthorizedEn { - _StringsDialogsLocalNetworkUnauthorizedFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsDialogsLocalNetworkUnauthorizedFr extends _StringsDialogsLocalNetworkUnauthorizedEn { + _StringsDialogsLocalNetworkUnauthorizedFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => '${_root.dialogs.noPermission.title}'; @@ -697,10 +697,10 @@ class _StringsDialogsLocalNetworkUnauthorizedFrFr extends _StringsDialogsLocalNe } // Path: dialogs.messageInput -class _StringsDialogsMessageInputFrFr extends _StringsDialogsMessageInputEn { - _StringsDialogsMessageInputFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsDialogsMessageInputFr extends _StringsDialogsMessageInputEn { + _StringsDialogsMessageInputFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Tapez un message'; @@ -708,10 +708,10 @@ class _StringsDialogsMessageInputFrFr extends _StringsDialogsMessageInputEn { } // Path: dialogs.noFiles -class _StringsDialogsNoFilesFrFr extends _StringsDialogsNoFilesEn { - _StringsDialogsNoFilesFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsDialogsNoFilesFr extends _StringsDialogsNoFilesEn { + _StringsDialogsNoFilesFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Aucun fichier sélectionné'; @@ -719,10 +719,10 @@ class _StringsDialogsNoFilesFrFr extends _StringsDialogsNoFilesEn { } // Path: dialogs.noPermission -class _StringsDialogsNoPermissionFrFr extends _StringsDialogsNoPermissionEn { - _StringsDialogsNoPermissionFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsDialogsNoPermissionFr extends _StringsDialogsNoPermissionEn { + _StringsDialogsNoPermissionFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Pas la permission'; @@ -730,10 +730,10 @@ class _StringsDialogsNoPermissionFrFr extends _StringsDialogsNoPermissionEn { } // Path: dialogs.notAvailableOnPlatform -class _StringsDialogsNotAvailableOnPlatformFrFr extends _StringsDialogsNotAvailableOnPlatformEn { - _StringsDialogsNotAvailableOnPlatformFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsDialogsNotAvailableOnPlatformFr extends _StringsDialogsNotAvailableOnPlatformEn { + _StringsDialogsNotAvailableOnPlatformFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Non disponible'; @@ -741,20 +741,20 @@ class _StringsDialogsNotAvailableOnPlatformFrFr extends _StringsDialogsNotAvaila } // Path: dialogs.qr -class _StringsDialogsQrFrFr extends _StringsDialogsQrEn { - _StringsDialogsQrFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsDialogsQrFr extends _StringsDialogsQrEn { + _StringsDialogsQrFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'QR Code'; } // Path: dialogs.quickActions -class _StringsDialogsQuickActionsFrFr extends _StringsDialogsQuickActionsEn { - _StringsDialogsQuickActionsFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsDialogsQuickActionsFr extends _StringsDialogsQuickActionsEn { + _StringsDialogsQuickActionsFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Actions Rapides'; @@ -766,10 +766,10 @@ class _StringsDialogsQuickActionsFrFr extends _StringsDialogsQuickActionsEn { } // Path: dialogs.quickSaveNotice -class _StringsDialogsQuickSaveNoticeFrFr extends _StringsDialogsQuickSaveNoticeEn { - _StringsDialogsQuickSaveNoticeFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsDialogsQuickSaveNoticeFr extends _StringsDialogsQuickSaveNoticeEn { + _StringsDialogsQuickSaveNoticeFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => '${_root.general.quickSave}'; @@ -777,10 +777,10 @@ class _StringsDialogsQuickSaveNoticeFrFr extends _StringsDialogsQuickSaveNoticeE } // Path: dialogs.sendModeHelp -class _StringsDialogsSendModeHelpFrFr extends _StringsDialogsSendModeHelpEn { - _StringsDialogsSendModeHelpFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsDialogsSendModeHelpFr extends _StringsDialogsSendModeHelpEn { + _StringsDialogsSendModeHelpFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get title => 'Modes d\'envoi'; @@ -790,10 +790,10 @@ class _StringsDialogsSendModeHelpFrFr extends _StringsDialogsSendModeHelpEn { } // Path: settingsTab.general.brightnessOptions -class _StringsSettingsTabGeneralBrightnessOptionsFrFr extends _StringsSettingsTabGeneralBrightnessOptionsEn { - _StringsSettingsTabGeneralBrightnessOptionsFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsSettingsTabGeneralBrightnessOptionsFr extends _StringsSettingsTabGeneralBrightnessOptionsEn { + _StringsSettingsTabGeneralBrightnessOptionsFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get system => 'Système'; @@ -802,10 +802,10 @@ class _StringsSettingsTabGeneralBrightnessOptionsFrFr extends _StringsSettingsTa } // Path: settingsTab.general.colorOptions -class _StringsSettingsTabGeneralColorOptionsFrFr extends _StringsSettingsTabGeneralColorOptionsEn { - _StringsSettingsTabGeneralColorOptionsFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsSettingsTabGeneralColorOptionsFr extends _StringsSettingsTabGeneralColorOptionsEn { + _StringsSettingsTabGeneralColorOptionsFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get system => 'Système'; @@ -813,20 +813,20 @@ class _StringsSettingsTabGeneralColorOptionsFrFr extends _StringsSettingsTabGene } // Path: settingsTab.general.languageOptions -class _StringsSettingsTabGeneralLanguageOptionsFrFr extends _StringsSettingsTabGeneralLanguageOptionsEn { - _StringsSettingsTabGeneralLanguageOptionsFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsSettingsTabGeneralLanguageOptionsFr extends _StringsSettingsTabGeneralLanguageOptionsEn { + _StringsSettingsTabGeneralLanguageOptionsFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String get system => 'Système'; } // Path: progressPage.total.title -class _StringsProgressPageTotalTitleFrFr extends _StringsProgressPageTotalTitleEn { - _StringsProgressPageTotalTitleFrFr._(_StringsFrFr root) : this._root = root, super._(root); +class _StringsProgressPageTotalTitleFr extends _StringsProgressPageTotalTitleEn { + _StringsProgressPageTotalTitleFr._(_StringsFr root) : this._root = root, super._(root); - @override final _StringsFrFr _root; // ignore: unused_field + @override final _StringsFr _root; // ignore: unused_field // Translations @override String sending({required Object time}) => 'Progression totale (${time})'; diff --git a/app/lib/pages/about/translators.dart b/app/lib/pages/about/translators.dart index 8bcd9c97f7e..3d34f5542a6 100644 --- a/app/lib/pages/about/translators.dart +++ b/app/lib/pages/about/translators.dart @@ -12,7 +12,7 @@ const _translators = >{ AppLocale.en: ['Tien Do Nam (@Tienisto)'], AppLocale.esEs: ['Esteban Daniel Saracho (@esaracho)'], AppLocale.fa: ['@farshad991'], - AppLocale.frFr: ['@Nixuge'], + AppLocale.fr: ['@Nixuge'], AppLocale.he: ['@ShlomoCode'], AppLocale.hu: ['@gidano'], AppLocale.it: ['@Francesco146'], diff --git a/app/macos/Runner/Info.plist b/app/macos/Runner/Info.plist index 3d49f836fc1..74ef78e2cbe 100644 --- a/app/macos/Runner/Info.plist +++ b/app/macos/Runner/Info.plist @@ -48,7 +48,7 @@ es-ES eu fa - fr-FR + fr he hu id diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 26f4ab63a47..d9a0380faf8 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -103,7 +103,7 @@ msix_config: # publisher: CN=0A8E9755-183F-4F0B-823F-1B8C991D7B97 identity_name: 11157TienDoNam.LocalSend logo_path: assets\img\logo-512.png - languages: en, ar, bn, cs, de, el, es-ES, eu, fa, fr-FR, he, hu, in, it, ja, ko, ne, nl, pl, pt-BR, ru, sv, th, tr, uk, vi, zh-CN, zh-HK, zh-TW + languages: en, ar, bn, cs, de, el, es-ES, eu, fa, fr, he, hu, in, it, ja, ko, ne, nl, pl, pt-BR, ru, sv, th, tr, uk, vi, zh-CN, zh-HK, zh-TW # https://github.com/localsend/localsend/issues/398 os_min_version: 10.0.19041.0 From 2cf6b486807829cf2795371c75194d63ea5cb4e0 Mon Sep 17 00:00:00 2001 From: Tien Do Nam Date: Sun, 19 Nov 2023 01:49:13 +0100 Subject: [PATCH 29/31] feat: add link to github tag --- app/lib/pages/about/about_page.dart | 75 +++++++++++++++++++++++++-- app/lib/pages/about/contributors.dart | 18 +++++-- 2 files changed, 86 insertions(+), 7 deletions(-) diff --git a/app/lib/pages/about/about_page.dart b/app/lib/pages/about/about_page.dart index b7946699b9c..8d3a9383ced 100644 --- a/app/lib/pages/about/about_page.dart +++ b/app/lib/pages/about/about_page.dart @@ -1,3 +1,5 @@ +import 'package:collection/collection.dart'; +import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:localsend_app/gen/strings.g.dart'; import 'package:localsend_app/pages/debug/debug_page.dart'; @@ -10,11 +12,14 @@ part 'contributors.dart'; part 'translators.dart'; +final _translatorWithGithubRegex = RegExp(r'(.+) \(@([\w\-_]+)\)'); + class AboutPage extends StatelessWidget { const AboutPage(); @override Widget build(BuildContext context) { + final primaryColor = Theme.of(context).colorScheme.primary; return Scaffold( appBar: AppBar( title: Text(t.aboutPage.title), @@ -37,13 +42,22 @@ class AboutPage extends StatelessWidget { child: const Text('localsend.org'), ), ), + const SizedBox(height: 10), Text(t.aboutPage.description.join('\n\n')), const SizedBox(height: 20), Text(t.aboutPage.author, style: const TextStyle(fontWeight: FontWeight.bold)), - const Text('Tien Do Nam (@Tienisto)'), + Text.rich(_buildContributor( + label: 'Tien Do Nam (@Tienisto)', + primaryColor: primaryColor, + )), const SizedBox(height: 20), Text(t.aboutPage.contributors, style: const TextStyle(fontWeight: FontWeight.bold)), - ..._contributors.map((e) => Text(e)), + ..._contributors.map((contributor) { + return Text.rich(_buildContributor( + label: contributor, + primaryColor: primaryColor, + )); + }), const SizedBox(height: 20), Text(t.aboutPage.translators, style: const TextStyle(fontWeight: FontWeight.bold)), Table( @@ -59,13 +73,25 @@ class AboutPage extends StatelessWidget { padding: const EdgeInsets.only(right: 10), child: Text(e.key.translations.locale), ), - Text(e.value.join('\n')), + Text.rich( + TextSpan( + children: e.value.mapIndexed( + (index, translator) { + return _buildContributor( + label: translator, + primaryColor: primaryColor, + newLine: index != 0, + ); + }, + ).toList(), + ), + ), ], ), ), ], ), - const SizedBox(height: 10), + const SizedBox(height: 20), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -107,3 +133,44 @@ class AboutPage extends StatelessWidget { ); } } + +/// Displays the contributor name and links to their github profile. +InlineSpan _buildContributor({required String label, required Color primaryColor, bool newLine = false}) { + final newLineStr = newLine ? '\n' : ''; + + if (label.startsWith('@')) { + // Only github name + return TextSpan( + text: '$newLineStr$label', + style: TextStyle(color: primaryColor), + recognizer: TapGestureRecognizer() + ..onTap = () async { + await launchUrl(Uri.parse('https://github.com/${label.substring(1)}'), mode: LaunchMode.externalApplication); + }, + ); + } + + final match = _translatorWithGithubRegex.firstMatch(label); + if (match != null) { + // Full name and github name + final fullName = match.group(1)!; + final githubName = match.group(2)!; + return TextSpan( + children: [ + TextSpan(text: '$newLineStr$fullName'), + const TextSpan(text: ' '), + TextSpan( + text: '@$githubName', + style: TextStyle(color: primaryColor), + recognizer: TapGestureRecognizer() + ..onTap = () async { + await launchUrl(Uri.parse('https://github.com/$githubName'), mode: LaunchMode.externalApplication); + }, + ), + ], + ); + } + + // Only full name + return TextSpan(text: '$newLineStr$label'); +} diff --git a/app/lib/pages/about/contributors.dart b/app/lib/pages/about/contributors.dart index d039515753f..2e30274406d 100644 --- a/app/lib/pages/about/contributors.dart +++ b/app/lib/pages/about/contributors.dart @@ -1,7 +1,19 @@ part of 'about_page.dart'; -/// Contributors who made several contributions to the project. +/// Contributors who made several contributions to the project or +/// who is maintainer of one of the distribution channels. /// Translators should not be listed here. -const _contributors = [ - 'Gabriel Lima (@TheGB0077)' +const _contributors = [ + 'Gabriel Lima (@TheGB0077)', + '@gitstart', + ..._packageMaintainers, +]; + +/// Maintainers of one of the distribution channels. +const _packageMaintainers = [ + '@brogers5', + '@Nixuge', + '@proletarius101', + '@sikmir', + '@sitiom', ]; From 88fa8b706542ccb16b3efe62c7e3bb344afe85f5 Mon Sep 17 00:00:00 2001 From: Tien Do Nam Date: Sun, 19 Nov 2023 02:10:59 +0100 Subject: [PATCH 30/31] fix(ios): fix permission error when picking directory --- app/assets/CHANGELOG.md | 1 + app/lib/util/native/pick_directory_path.dart | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/assets/CHANGELOG.md b/app/assets/CHANGELOG.md index d1130841917..68c69c9bf7b 100644 --- a/app/assets/CHANGELOG.md +++ b/app/assets/CHANGELOG.md @@ -4,6 +4,7 @@ - feat: add donation options (@Tienisto) - feat(macos): add Command+W shortcut to close the window (@Q1CHENL) - fix: also show an OLED color mode option when dynamic colors are not supported by OS (@dhruvanbhalara) +- fix(ios): fix permission error when picking directory (@Tienisto) - i18n: add Greek (@multipetros) ## 1.12.0 (2023-10-25) diff --git a/app/lib/util/native/pick_directory_path.dart b/app/lib/util/native/pick_directory_path.dart index c489884dc68..57df8d077b0 100644 --- a/app/lib/util/native/pick_directory_path.dart +++ b/app/lib/util/native/pick_directory_path.dart @@ -6,11 +6,11 @@ import 'package:localsend_app/util/native/platform_check.dart'; /// Opens a file picker to select a directory. /// Returns null if the user cancels the selection. Future pickDirectoryPath() async { - if (checkPlatform([TargetPlatform.android])) { + if (checkPlatform([TargetPlatform.android, TargetPlatform.iOS])) { /// We need to use the file_picker package because file_selector does not expose the raw path. /// We need the raw path to properly manipulate the path to save new files, or /// to list files recursively. - /// https://github.com/miguelpruivo/flutter_file_picker/issues/1282 + /// Also, on iOS, file_selector does not work with directories. return await FilePicker.platform.getDirectoryPath(); } else { return await file_selector.getDirectoryPath(); From 71ff31899ba949dde941c4571106e7b953a0d972 Mon Sep 17 00:00:00 2001 From: Tien Do Nam <38380847+Tienisto@users.noreply.github.com> Date: Sun, 19 Nov 2023 02:41:22 +0100 Subject: [PATCH 31/31] feat: add Yaru theme (#912) --- app/assets/CHANGELOG.md | 1 + app/lib/model/persistence/color_mode.dart | 1 + app/lib/pages/receive_page.dart | 16 ++++--- app/lib/pages/tabs/receive_tab.dart | 4 +- app/lib/pages/tabs/settings_tab.dart | 14 +++--- app/lib/pages/troubleshoot_page.dart | 4 +- app/lib/theme.dart | 48 +++++++++++++++++++ .../dialogs/file_name_input_dialog.dart | 4 +- .../widget/dialogs/message_input_dialog.dart | 4 +- .../widget/dialogs/quick_actions_dialog.dart | 4 +- app/lib/widget/dialogs/text_field_tv.dart | 4 +- .../flutter/generated_plugin_registrant.cc | 4 ++ app/linux/flutter/generated_plugins.cmake | 1 + app/pubspec.lock | 16 +++++++ app/pubspec.yaml | 1 + 15 files changed, 100 insertions(+), 26 deletions(-) diff --git a/app/assets/CHANGELOG.md b/app/assets/CHANGELOG.md index 68c69c9bf7b..8f65c0c5375 100644 --- a/app/assets/CHANGELOG.md +++ b/app/assets/CHANGELOG.md @@ -2,6 +2,7 @@ - feat: ignore duplicate files when selected from file picker (@programmermager) - feat: add donation options (@Tienisto) +- feat: add Yaru theme (@Tienisto) - feat(macos): add Command+W shortcut to close the window (@Q1CHENL) - fix: also show an OLED color mode option when dynamic colors are not supported by OS (@dhruvanbhalara) - fix(ios): fix permission error when picking directory (@Tienisto) diff --git a/app/lib/model/persistence/color_mode.dart b/app/lib/model/persistence/color_mode.dart index 08d4e79b48f..29bf81628d4 100644 --- a/app/lib/model/persistence/color_mode.dart +++ b/app/lib/model/persistence/color_mode.dart @@ -2,4 +2,5 @@ enum ColorMode { system, // dynamic colors localsend, oled, + yaru, } diff --git a/app/lib/pages/receive_page.dart b/app/lib/pages/receive_page.dart index 7e19da787f1..9fbc8f62fe7 100644 --- a/app/lib/pages/receive_page.dart +++ b/app/lib/pages/receive_page.dart @@ -3,11 +3,13 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:localsend_app/gen/strings.g.dart'; +import 'package:localsend_app/model/persistence/color_mode.dart'; import 'package:localsend_app/model/session_status.dart'; import 'package:localsend_app/pages/progress_page.dart'; import 'package:localsend_app/pages/receive_options_page.dart'; import 'package:localsend_app/provider/network/server/server_provider.dart'; import 'package:localsend_app/provider/selection/selected_receiving_files_provider.dart'; +import 'package:localsend_app/provider/settings_provider.dart'; import 'package:localsend_app/theme.dart'; import 'package:localsend_app/util/ip_helper.dart'; import 'package:localsend_app/util/native/platform_check.dart'; @@ -73,6 +75,7 @@ class _ReceivePageState extends State with Refena { ); } final selectedFiles = ref.watch(selectedReceivingFilesProvider); + final colorMode = ref.watch(settingsProvider.select((state) => state.colorMode)); return WillPopScope( onWillPop: () async { @@ -182,8 +185,8 @@ class _ReceivePageState extends State with Refena { padding: const EdgeInsets.only(left: 20), child: ElevatedButton( style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).buttonTheme.colorScheme!.primary, - foregroundColor: Theme.of(context).buttonTheme.colorScheme!.onPrimary, + backgroundColor: Theme.of(context).colorScheme.primary, + foregroundColor: Theme.of(context).colorScheme.onPrimary, ), onPressed: () { // ignore: discarded_futures @@ -254,8 +257,9 @@ class _ReceivePageState extends State with Refena { children: [ ElevatedButton.icon( style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).colorScheme.error, - foregroundColor: Theme.of(context).colorScheme.onError, + elevation: colorMode == ColorMode.yaru ? 0 : null, + backgroundColor: colorMode == ColorMode.yaru ? Theme.of(context).colorScheme.background : Theme.of(context).colorScheme.error, + foregroundColor: colorMode == ColorMode.yaru ? Theme.of(context).colorScheme.onBackground : Theme.of(context).colorScheme.onError, ), onPressed: () { _decline(); @@ -267,8 +271,8 @@ class _ReceivePageState extends State with Refena { const SizedBox(width: 20), ElevatedButton.icon( style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).buttonTheme.colorScheme!.primary, - foregroundColor: Theme.of(context).buttonTheme.colorScheme!.onPrimary, + backgroundColor: Theme.of(context).colorScheme.primary, + foregroundColor: Theme.of(context).colorScheme.onPrimary, ), onPressed: selectedFiles.isEmpty ? null diff --git a/app/lib/pages/tabs/receive_tab.dart b/app/lib/pages/tabs/receive_tab.dart index 839f85f75bb..d4ede7c080f 100644 --- a/app/lib/pages/tabs/receive_tab.dart +++ b/app/lib/pages/tabs/receive_tab.dart @@ -76,8 +76,8 @@ class ReceiveTab extends StatelessWidget { child: vm.quickSaveSettings ? ElevatedButton( style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).buttonTheme.colorScheme!.primary, - foregroundColor: Theme.of(context).buttonTheme.colorScheme!.onPrimary, + backgroundColor: Theme.of(context).colorScheme.primary, + foregroundColor: Theme.of(context).colorScheme.onPrimary, ), onPressed: () async => vm.onSetQuickSave(context, false), child: Text('${t.general.quickSave}: ${t.general.on}'), diff --git a/app/lib/pages/tabs/settings_tab.dart b/app/lib/pages/tabs/settings_tab.dart index 40478b75c4f..0295d2c12d9 100644 --- a/app/lib/pages/tabs/settings_tab.dart +++ b/app/lib/pages/tabs/settings_tab.dart @@ -625,13 +625,11 @@ extension on ThemeMode { extension on ColorMode { String get humanName { - switch (this) { - case ColorMode.system: - return t.settingsTab.general.colorOptions.system; - case ColorMode.localsend: - return t.appName; - case ColorMode.oled: - return t.settingsTab.general.colorOptions.oled; - } + return switch (this) { + ColorMode.system => t.settingsTab.general.colorOptions.system, + ColorMode.localsend => t.appName, + ColorMode.oled => t.settingsTab.general.colorOptions.oled, + ColorMode.yaru => 'Yaru', + }; } } diff --git a/app/lib/pages/troubleshoot_page.dart b/app/lib/pages/troubleshoot_page.dart index 69a3c15cd5f..0c32bf4e3eb 100644 --- a/app/lib/pages/troubleshoot_page.dart +++ b/app/lib/pages/troubleshoot_page.dart @@ -156,8 +156,8 @@ class _FixButton extends StatelessWidget { Widget build(BuildContext context) { return ElevatedButton( style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).buttonTheme.colorScheme!.primary, - foregroundColor: Theme.of(context).buttonTheme.colorScheme!.onPrimary, + backgroundColor: Theme.of(context).colorScheme.primary, + foregroundColor: Theme.of(context).colorScheme.onPrimary, ), onPressed: () async { if (onTap != null) { diff --git a/app/lib/theme.dart b/app/lib/theme.dart index d560f90bd85..4dbe4303179 100644 --- a/app/lib/theme.dart +++ b/app/lib/theme.dart @@ -6,10 +6,15 @@ import 'package:localsend_app/provider/device_info_provider.dart'; import 'package:localsend_app/util/native/platform_check.dart'; import 'package:localsend_app/util/ui/dynamic_colors.dart'; import 'package:refena_flutter/refena_flutter.dart'; +import 'package:yaru/yaru.dart' as yaru; final _borderRadius = BorderRadius.circular(5); ThemeData getTheme(ColorMode colorMode, Brightness brightness, DynamicColors? dynamicColors) { + if (colorMode == ColorMode.yaru) { + return _getYaruTheme(brightness); + } + final colorScheme = _determineColorScheme(colorMode, brightness, dynamicColors); final lightInputBorder = OutlineInputBorder( @@ -134,7 +139,50 @@ ColorScheme _determineColorScheme(ColorMode mode, Brightness brightness, Dynamic background: Colors.black, surface: Colors.black, ), + ColorMode.yaru => throw 'Should reach here', }; return colorScheme ?? defaultColorScheme; } + +ThemeData _getYaruTheme(Brightness brightness) { + final baseTheme = brightness == Brightness.light ? yaru.yaruLight : yaru.yaruDark; + final colorScheme = baseTheme.colorScheme; + + final lightInputBorder = OutlineInputBorder( + borderSide: BorderSide(color: colorScheme.secondaryContainer), + borderRadius: _borderRadius, + ); + + final darkInputBorder = OutlineInputBorder( + borderSide: BorderSide(color: colorScheme.secondaryContainer), + borderRadius: _borderRadius, + ); + + return baseTheme.copyWith( + navigationBarTheme: colorScheme.brightness == Brightness.dark + ? NavigationBarThemeData( + iconTheme: MaterialStateProperty.all(const IconThemeData(color: Colors.white)), + ) + : null, + inputDecorationTheme: InputDecorationTheme( + filled: true, + fillColor: colorScheme.secondaryContainer, + border: colorScheme.brightness == Brightness.light ? lightInputBorder : darkInputBorder, + focusedBorder: colorScheme.brightness == Brightness.light ? lightInputBorder : darkInputBorder, + enabledBorder: colorScheme.brightness == Brightness.light ? lightInputBorder : darkInputBorder, + contentPadding: const EdgeInsets.symmetric(vertical: 0, horizontal: 10), + ), + elevatedButtonTheme: ElevatedButtonThemeData( + style: ElevatedButton.styleFrom( + foregroundColor: colorScheme.brightness == Brightness.dark ? Colors.white : null, + padding: checkPlatformIsDesktop() ? const EdgeInsets.all(16) : const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + ), + ), + textButtonTheme: TextButtonThemeData( + style: TextButton.styleFrom( + padding: checkPlatformIsDesktop() ? const EdgeInsets.all(16) : const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + ), + ), + ); +} diff --git a/app/lib/widget/dialogs/file_name_input_dialog.dart b/app/lib/widget/dialogs/file_name_input_dialog.dart index f7ddfea2a1d..8d62a9cee23 100644 --- a/app/lib/widget/dialogs/file_name_input_dialog.dart +++ b/app/lib/widget/dialogs/file_name_input_dialog.dart @@ -60,8 +60,8 @@ class _FileNameInputDialogState extends State { ), ElevatedButton( style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).buttonTheme.colorScheme!.primary, - foregroundColor: Theme.of(context).buttonTheme.colorScheme!.onPrimary, + backgroundColor: Theme.of(context).colorScheme.primary, + foregroundColor: Theme.of(context).colorScheme.onPrimary, ), onPressed: _submit, child: Text(t.general.confirm), diff --git a/app/lib/widget/dialogs/message_input_dialog.dart b/app/lib/widget/dialogs/message_input_dialog.dart index db16fed91ff..f1d89fc1e83 100644 --- a/app/lib/widget/dialogs/message_input_dialog.dart +++ b/app/lib/widget/dialogs/message_input_dialog.dart @@ -43,8 +43,8 @@ class _MessageInputDialogState extends State { ), ElevatedButton( style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).buttonTheme.colorScheme!.primary, - foregroundColor: Theme.of(context).buttonTheme.colorScheme!.onPrimary, + backgroundColor: Theme.of(context).colorScheme.primary, + foregroundColor: Theme.of(context).colorScheme.onPrimary, ), onPressed: () => context.pop(_textController.text), child: Text(t.general.confirm), diff --git a/app/lib/widget/dialogs/quick_actions_dialog.dart b/app/lib/widget/dialogs/quick_actions_dialog.dart index fcd991a6a5f..8a01256d247 100644 --- a/app/lib/widget/dialogs/quick_actions_dialog.dart +++ b/app/lib/widget/dialogs/quick_actions_dialog.dart @@ -112,8 +112,8 @@ class _QuickActionsDialogState extends State with Refena { ), ElevatedButton( style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).buttonTheme.colorScheme!.primary, - foregroundColor: Theme.of(context).buttonTheme.colorScheme!.onPrimary, + backgroundColor: Theme.of(context).colorScheme.primary, + foregroundColor: Theme.of(context).colorScheme.onPrimary, ), onPressed: () { switch (_action) { diff --git a/app/lib/widget/dialogs/text_field_tv.dart b/app/lib/widget/dialogs/text_field_tv.dart index 7b618f3c8a5..ef27c8ea1a8 100644 --- a/app/lib/widget/dialogs/text_field_tv.dart +++ b/app/lib/widget/dialogs/text_field_tv.dart @@ -50,8 +50,8 @@ class _TextFieldTvState extends State with Refena { actions: [ ElevatedButton( style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).buttonTheme.colorScheme!.primary, - foregroundColor: Theme.of(context).buttonTheme.colorScheme!.onPrimary, + backgroundColor: Theme.of(context).colorScheme.primary, + foregroundColor: Theme.of(context).colorScheme.onPrimary, ), onPressed: () => context.pop(), child: Text(t.general.confirm), diff --git a/app/linux/flutter/generated_plugin_registrant.cc b/app/linux/flutter/generated_plugin_registrant.cc index da9a7982383..999deafd72f 100644 --- a/app/linux/flutter/generated_plugin_registrant.cc +++ b/app/linux/flutter/generated_plugin_registrant.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); file_selector_plugin_register_with_registrar(file_selector_linux_registrar); + g_autoptr(FlPluginRegistrar) gtk_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "GtkPlugin"); + gtk_plugin_register_with_registrar(gtk_registrar); g_autoptr(FlPluginRegistrar) pasteboard_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin"); pasteboard_plugin_register_with_registrar(pasteboard_registrar); diff --git a/app/linux/flutter/generated_plugins.cmake b/app/linux/flutter/generated_plugins.cmake index a549c821c4f..bf78cd7da38 100644 --- a/app/linux/flutter/generated_plugins.cmake +++ b/app/linux/flutter/generated_plugins.cmake @@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST desktop_drop dynamic_color file_selector_linux + gtk pasteboard screen_retriever system_tray diff --git a/app/pubspec.lock b/app/pubspec.lock index 88ff2f04c88..c1cee4a4c29 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -580,6 +580,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.1" + gtk: + dependency: transitive + description: + name: gtk + sha256: e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c + url: "https://pub.dev" + source: hosted + version: "2.1.0" html: dependency: transitive description: @@ -1731,6 +1739,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.2" + yaru: + dependency: "direct main" + description: + name: yaru + sha256: "037219db9ffe757eae0d929cb9dc1a8b27af9850dc6c0d89ecf597dc4f78a5b6" + url: "https://pub.dev" + source: hosted + version: "1.2.0" sdks: dart: ">=3.1.1 <4.0.0" flutter: ">=3.13.1" diff --git a/app/pubspec.yaml b/app/pubspec.yaml index d9a0380faf8..4395f595ea3 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -68,6 +68,7 @@ dependencies: wakelock_plus: 1.1.3 wechat_assets_picker: 8.7.1 window_manager: 0.3.7 + yaru: 1.2.0 dev_dependencies: build_runner: 2.4.6