From 626313fbcaec09e289880eff70eb7da38a29bcb9 Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Tue, 26 Nov 2024 15:17:03 +0100 Subject: [PATCH 1/4] Fix/ Manual update rooted (#1439) * fix rooted update check & add spiner * change version for test * show error failed * add internet check & disable update button * fix trailing space --- .../main/kotlin/com/flyweb/MainActivity.kt | 62 +++++++++---------- lib/l10n/intl_ar.arb | 17 ++++- lib/l10n/intl_en.arb | 18 +++++- lib/l10n/intl_fr.arb | 17 ++++- lib/src/pages/SettingScreen.dart | 54 +++++++++++++--- .../manual_update_notifier.dart | 33 ++++++---- .../manual_update_state.dart | 8 +++ lib/src/widgets/manual_update_dialog.dart | 25 +++++++- pubspec.yaml | 2 +- 9 files changed, 177 insertions(+), 59 deletions(-) diff --git a/android/app/src/main/kotlin/com/flyweb/MainActivity.kt b/android/app/src/main/kotlin/com/flyweb/MainActivity.kt index c2334df43..f4e5da4fd 100644 --- a/android/app/src/main/kotlin/com/flyweb/MainActivity.kt +++ b/android/app/src/main/kotlin/com/flyweb/MainActivity.kt @@ -63,39 +63,35 @@ class MainActivity : FlutterActivity() { val isSuccess = clearDataRestart() result.success(isSuccess) } - "installApk" -> { - val filePath = call.argument("filePath") - if (filePath != null) { - AsyncTask.execute { - try { - // Check if file exists - val file = java.io.File(filePath) - if (!file.exists()) { - Log.e("APK_INSTALL", "APK file not found at path: $filePath") - result.error("FILE_NOT_FOUND", "APK file not found", null) - return@execute - } - // Check if device is rooted - if (!checkRoot()) { - Log.e("APK_INSTALL", "Device is not rooted") - result.error("NOT_ROOTED", "Device is not rooted", null) - return@execute - } - - - - executeCommand(listOf("pm install -r -d $filePath"), result) - - result.success("Installation initiated") - } catch (e: Exception) { - Log.e("APK_INSTALL", "Failed to install APK", e) - result.error("INSTALL_FAILED", e.message, null) - } - } - } else { - result.error("INVALID_PATH", "File path is null", null) - } -} + "installApk" -> { + val filePath = call.argument("filePath") + if (filePath != null) { + AsyncTask.execute { + try { + // Check if file exists + val file = java.io.File(filePath) + if (!file.exists()) { + Log.e("APK_INSTALL", "APK file not found at path: $filePath") + result.error("FILE_NOT_FOUND", "APK file not found", null) + return@execute + } + // Check if device is rooted + if (!checkRoot()) { + Log.e("APK_INSTALL", "Device is not rooted") + result.error("NOT_ROOTED", "Device is not rooted", null) + return@execute + } + val commands = listOf("pm install -r -d $filePath") + executeCommand(commands, result) + } catch (e: Exception) { + Log.e("APK_INSTALL", "Failed to install APK", e) + result.error("INSTALL_FAILED", e.message, null) + } + } + } else { + result.error("INVALID_PATH", "File path is null", null) + } + } else -> result.notImplemented() } } diff --git a/lib/l10n/intl_ar.arb b/lib/l10n/intl_ar.arb index 5c8460326..54e7020c4 100644 --- a/lib/l10n/intl_ar.arb +++ b/lib/l10n/intl_ar.arb @@ -364,5 +364,20 @@ "downloadingUpdate": "جارٍ تنزيل التحديث...", "installingUpdate": "جارٍ تثبيت التحديث...", "updateCompletedSuccessfully": "تم التحديث بنجاح", - "updateFailed": "فشل التحديث" + "updateFailed": "فشل التحديث", + "checkInternetUpdate": "يجب عليك الاتصال بالإنترنت للتحقق من وجود تحديثات جديدة", + "appUpdateAvailable": "تطبيقك يعمل بالإصدار {currentVersion}. تحديث جديد (الإصدار {updatedVersion}) متوفر مع أحدث الميزات والتحسينات.", + "@appUpdateAvailable": { + "description": "نص بديل لعرض رسالة التحديث المتاح", + "placeholders": { + "currentVersion": { + "type": "String", + "example": "1" + }, + "updatedVersion": { + "type": "String", + "example": "604" + } + } + } } diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 5f3d806c5..51c34c6a4 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -364,6 +364,22 @@ "downloadingUpdate": "Downloading update...", "installingUpdate": "Installing update...", "updateCompletedSuccessfully": "Update completed successfully", - "updateFailed": "Update failed" + "updateFailed": "Update failed", + "checkInternetUpdate": "You must connect to internet to check for new updates", + "appUpdateAvailable": "Your app is running version {currentVersion}. A new update (version {updatedVersion}) is available with the latest features and improvements.", + "@appUpdateAvailable": { + "description": "Placeholder text for displaying update available message", + "placeholders": { + "currentVersion": { + "type": "String", + "example": "1" + }, + "updatedVersion": { + "type": "String", + "example": "604" + } + } + } + } diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index d2040c0b0..2bce6e640 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -364,5 +364,20 @@ "downloadingUpdate": "Téléchargement de la mise à jour...", "installingUpdate": "Installation de la mise à jour...", "updateCompletedSuccessfully": "Mise à jour terminée avec succès", - "updateFailed": "Échec de la mise à jour" + "updateFailed": "Échec de la mise à jour", + "checkInternetUpdate": "Vous devez être connecté à Internet pour vérifier les nouvelles mises à jour", + "appUpdateAvailable": "Votre application utilise la version {currentVersion}. Une nouvelle mise à jour (version {updatedVersion}) est disponible avec les dernières fonctionnalités et améliorations.", + "@appUpdateAvailable": { + "description": "Texte de remplacement pour afficher le message de mise à jour disponible", + "placeholders": { + "currentVersion": { + "type": "String", + "example": "1" + }, + "updatedVersion": { + "type": "String", + "example": "604" + } + } + } } \ No newline at end of file diff --git a/lib/src/pages/SettingScreen.dart b/lib/src/pages/SettingScreen.dart index b414cfd49..01e6a6080 100644 --- a/lib/src/pages/SettingScreen.dart +++ b/lib/src/pages/SettingScreen.dart @@ -289,14 +289,52 @@ class _SettingScreenState extends ConsumerState { _SettingItem( title: S.of(context).checkForUpdates, subtitle: S.of(context).checkForNewVersion, - icon: const Icon(Icons.system_update, size: 35), - onTap: () async { - var softwareFuture = await PackageInfo.fromPlatform(); - - ref - .read(manualUpdateNotifierProvider.notifier) - .checkForUpdates(softwareFuture.version, context.read().appLocal.languageCode); - }, + icon: ref.watch(manualUpdateNotifierProvider).isLoading + ? const SizedBox( + width: 35, + height: 35, + child: CircularProgressIndicator(), + ) + : const Icon(Icons.system_update, size: 35), + onTap: ref.watch(manualUpdateNotifierProvider).isLoading + ? null + : () async { + await ref.read(connectivityProvider.notifier).checkInternetConnection(); + ref.watch(connectivityProvider).maybeWhen( + orElse: () { + showCheckInternetDialog( + context: context, + onRetry: () { + AppRouter.pop(); + }, + title: checkInternet, + content: S.of(context).checkInternetUpdate, + ); + }, + data: (isConnectedToInternet) async { + if (isConnectedToInternet == ConnectivityStatus.disconnected) { + showCheckInternetDialog( + context: context, + onRetry: () { + AppRouter.pop(); + }, + title: checkInternet, + content: S.of(context).checkInternetUpdate, + ); + } else { + var softwareFuture = await PackageInfo.fromPlatform(); + final isDeviceRooted = ref.watch(onBoardingProvider).maybeWhen( + orElse: () => false, + data: (value) => value.isRootedDevice, + ); + ref.read(manualUpdateNotifierProvider.notifier).checkForUpdates( + softwareFuture.version, + context.read().appLocal.languageCode, + isDeviceRooted); + } + }, + ); + }, ), ], ), diff --git a/lib/src/state_management/manual_app_update/manual_update_notifier.dart b/lib/src/state_management/manual_app_update/manual_update_notifier.dart index 34b671b97..916474047 100644 --- a/lib/src/state_management/manual_app_update/manual_update_notifier.dart +++ b/lib/src/state_management/manual_app_update/manual_update_notifier.dart @@ -51,31 +51,35 @@ class ManualUpdateNotifier extends AsyncNotifier { Future checkForUpdates( String currentVersion, - String languageCode, { - bool? isDeviceRooted, - }) async { + String languageCode, + bool isDeviceRooted, + ) async { + state = const AsyncLoading(); try { - state = const AsyncValue.data(UpdateState(status: UpdateStatus.checking, message: 'Checking updates...')); - - final hasUpdate = isDeviceRooted ?? false + final hasUpdate = isDeviceRooted ? await _isUpdateAvailableForRootedDevice(currentVersion) : await _isUpdateAvailableStandard(languageCode); if (hasUpdate) { final downloadUrl = await _getLatestReleaseUrl(); - state = AsyncValue.data(state.value!.copyWith( + final latestVersion = await _getLatestVersion(); + + state = AsyncData(state.value!.copyWith( status: UpdateStatus.available, message: 'Update available', downloadUrl: downloadUrl, + currentVersion: currentVersion, + availableVersion: latestVersion, )); } else { - state = const AsyncValue.data(UpdateState( + state = AsyncData(UpdateState( status: UpdateStatus.notAvailable, message: 'You are using the latest version', + currentVersion: currentVersion, )); } } catch (e, st) { - state = AsyncValue.error('Failed to check updates', st); + state = AsyncError(e, st); } } @@ -93,7 +97,6 @@ class ManualUpdateNotifier extends AsyncNotifier { (release) => release['prerelease'] == false, orElse: () => throw Exception('No stable release found'), ); - final latestVersion = latestRelease['tag_name'].toString(); return _compareVersions(latestVersion, currentVersion) > 0; } @@ -113,6 +116,15 @@ class ManualUpdateNotifier extends AsyncNotifier { return response.data as List; } + Future _getLatestVersion() async { + final releases = await _fetchReleases(); + final latestRelease = releases.firstWhere( + (release) => release['prerelease'] == false, + orElse: () => throw Exception('No stable release found'), + ); + return latestRelease['tag_name'].toString(); + } + Future downloadAndInstallUpdate() async { final downloadUrl = state.value?.downloadUrl; if (downloadUrl == null) return; @@ -243,7 +255,6 @@ class ManualUpdateNotifier extends AsyncNotifier { int _compareVersions(String v1, String v2) { final version1 = v1.replaceAll('v', '').split('.'); final version2 = v2.replaceAll('v', '').split('.'); - for (var i = 0; i < version1.length && i < version2.length; i++) { final num1 = int.parse(version1[i]); final num2 = int.parse(version2[i]); diff --git a/lib/src/state_management/manual_app_update/manual_update_state.dart b/lib/src/state_management/manual_app_update/manual_update_state.dart index 3dc37ee3d..57437b57b 100644 --- a/lib/src/state_management/manual_app_update/manual_update_state.dart +++ b/lib/src/state_management/manual_app_update/manual_update_state.dart @@ -19,6 +19,8 @@ class UpdateState extends Equatable { final String? error; final String? downloadUrl; final String? filePath; + final String? currentVersion; + final String? availableVersion; const UpdateState({ this.status = UpdateStatus.initial, @@ -27,6 +29,8 @@ class UpdateState extends Equatable { this.error, this.downloadUrl, this.filePath, + this.currentVersion, + this.availableVersion, }); UpdateState copyWith({ @@ -36,6 +40,8 @@ class UpdateState extends Equatable { String? error, String? downloadUrl, String? filePath, + String? currentVersion, + String? availableVersion, }) { return UpdateState( status: status ?? this.status, @@ -44,6 +50,8 @@ class UpdateState extends Equatable { error: error ?? this.error, downloadUrl: downloadUrl ?? this.downloadUrl, filePath: filePath ?? this.filePath, + currentVersion: currentVersion ?? this.currentVersion, + availableVersion: availableVersion ?? this.availableVersion, ); } diff --git a/lib/src/widgets/manual_update_dialog.dart b/lib/src/widgets/manual_update_dialog.dart index 3e3d05cc3..6e0367e96 100644 --- a/lib/src/widgets/manual_update_dialog.dart +++ b/lib/src/widgets/manual_update_dialog.dart @@ -11,7 +11,8 @@ class UpdateDialogMessages { static Map getLocalizedMessage(BuildContext context) { return { UpdateStatus.checking: S.of(context).checkingForUpdates, - UpdateStatus.available: S.of(context).updateAvailable, +/* UpdateStatus.available: S.of(context).updateAvailable, + */ UpdateStatus.notAvailable: S.of(context).usingLatestVersion, UpdateStatus.downloading: S.of(context).downloadingUpdate, UpdateStatus.installing: S.of(context).installingUpdate, @@ -46,7 +47,21 @@ class UpdateDialog { return Column( mainAxisSize: MainAxisSize.min, children: [ - Text(localizedMessages[updateState.value?.status] ?? S.of(context).wouldYouLikeToUpdate), + if (updateState.value?.currentVersion != null && updateState.value?.availableVersion != null) ...[ + Text(S.of(context).appUpdateAvailable( + updateState.value?.currentVersion as String, updateState.value?.availableVersion as String)), + const SizedBox(height: 8), + ], + if (updateState.value?.status == UpdateStatus.error) + Text( + updateState.value?.message ?? S.of(context).updateFailed, + style: TextStyle(color: Theme.of(context).colorScheme.error), + textAlign: TextAlign.center, + ) + else + Text( + localizedMessages[updateState.value?.status] ?? S.of(context).wouldYouLikeToUpdate, + ), if (updateState.value?.progress != null) ...[ const SizedBox(height: 16), LinearProgressIndicator( @@ -67,6 +82,10 @@ class UpdateDialog { } static List _buildDialogActions(BuildContext context, WidgetRef ref) { + final updateState = ref.watch(manualUpdateNotifierProvider); + final isUpdating = + updateState.value?.status == UpdateStatus.downloading || updateState.value?.status == UpdateStatus.installing; + return [ TextButton( onPressed: () { @@ -76,7 +95,7 @@ class UpdateDialog { child: Text(S.of(context).cancel), ), TextButton( - onPressed: () => _handleUpdateAction(context, ref), + onPressed: isUpdating ? null : () => _handleUpdateAction(context, ref), child: Text(S.of(context).update), ), ]; diff --git a/pubspec.yaml b/pubspec.yaml index 2a6ac6fbf..6e56dc273 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.17.1+1 +version: 1.17.0+1 environment: From ad76a398b8d243f17ebece21d92f4fac76522f95 Mon Sep 17 00:00:00 2001 From: Ibrahim ZEHHAF <97339607+ibrahim-zehhaf-mawaqit@users.noreply.github.com> Date: Wed, 27 Nov 2024 07:18:23 +0100 Subject: [PATCH 2/4] Update pubspec.yaml --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 6e56dc273..4c05a4b3c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.17.0+1 +version: 1.17.2+1 environment: From 76dfbce9a0b5e85a0233c3df60fb2e961bd070c2 Mon Sep 17 00:00:00 2001 From: Ibrahim ZEHHAF <97339607+ibrahim-zehhaf-mawaqit@users.noreply.github.com> Date: Wed, 27 Nov 2024 07:35:42 +0100 Subject: [PATCH 3/4] Update pubspec.yaml --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 4c05a4b3c..f797dae85 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.17.2+1 +version: 1.17.3+1 environment: From a651f91b250aa5357e15fc9acc339ab07e63fab8 Mon Sep 17 00:00:00 2001 From: Ibrahim ZEHHAF <97339607+ibrahim-zehhaf-mawaqit@users.noreply.github.com> Date: Wed, 27 Nov 2024 07:51:40 +0100 Subject: [PATCH 4/4] New Crowdin updates (#1435) * New translations intl_en.arb (ar) * New translations intl_en.arb (en) * New translations intl_en.arb (ar) * New translations intl_en.arb (pt) * New translations intl_en.arb (ar) * New translations intl_en.arb (fr) --- lib/l10n/intl_ar.arb | 58 +++++++++++++++++++++--------------------- lib/l10n/intl_en.arb | 11 ++++---- lib/l10n/intl_fr.arb | 2 +- lib/l10n/intl_pt.arb | 60 ++++++++++++++++++++++++++++++++++++++------ 4 files changed, 87 insertions(+), 44 deletions(-) diff --git a/lib/l10n/intl_ar.arb b/lib/l10n/intl_ar.arb index 54e7020c4..91efe82db 100644 --- a/lib/l10n/intl_ar.arb +++ b/lib/l10n/intl_ar.arb @@ -68,19 +68,19 @@ "@azkarList1": { "description": "سُـبْحانَ اللهِ، والحَمْـدُ لله، واللهُ أكْـبَر 33 مرة لا إِلَٰهَ إلاّ اللّهُ وَحْـدَهُ لا شريكَ لهُ، لهُ الملكُ ولهُ الحَمْد، وهُوَ على كُلّ شَيءٍ قَـدير" }, - "azkarList2": "بِسۡمِ ٱللَّهِ ٱلرَّحۡمَٰنِ ٱلرَّحِيمِ قُلۡ أَعُوذُ بِرَبِّ ٱلنَّاسِ ، مَلِكِ ٱلنَّاسِ ، إِلَٰهِ ٱلنَّاسِ ، مِن شَرِّ ٱلۡوَسۡوَاسِ ٱلۡخَنَّاسِ ، ٱلَّذِي يُوَسۡوِسُ فِي صُدُورِ ٱلنَّاسِ ، مِنَ ٱلۡجِنَّةِ وَٱلنَّاس", + "azkarList2": "", "@azkarList2": { "description": "بِسۡمِ ٱللَّهِ ٱلرَّحۡمَٰنِ ٱلرَّحِيمِ قُلۡ أَعُوذُ بِرَبِّ ٱلنَّاسِ ، مَلِكِ ٱلنَّاسِ ، إِلَٰهِ ٱلنَّاسِ ، مِن شَرِّ ٱلۡوَسۡوَاسِ ٱلۡخَنَّاسِ ، ٱلَّذِي يُوَسۡوِسُ فِي صُدُورِ ٱلنَّاسِ ، مِنَ ٱلۡجِنَّةِ وَٱلنَّاس" }, - "azkarList3": "بِسۡمِ ٱللَّهِ ٱلرَّحۡمَٰنِ ٱلرَّحِيمِ قُلۡ أَعُوذُ بِرَبِّ ٱلۡفَلَقِ ، مِن شَرِّ مَا خَلَقَ ، وَمِن شَرِّ غَاسِقٍ إِذَا وَقَبَ ، وَمِن شَرِ ٱلنَّفَّٰثَٰتِ فِي ٱلۡعُقَدِ ، وَمِن شَرِّ حَاسِدٍ إِذَا حَسَدَ", + "azkarList3": "", "@azkarList3": { "description": "بِسۡمِ ٱللَّهِ ٱلرَّحۡمَٰنِ ٱلرَّحِيمِقُلۡ أَعُوذُ بِرَبِّ ٱلۡفَلَقِ ، مِن شَرِّ مَا خَلَقَ ، وَمِن شَرِّ غَاسِقٍ إِذَا وَقَبَ ، وَمِن شَرِ ٱلنَّفَّٰثَٰتِ فِي ٱلۡعُقَدِ ، وَمِن شَرِّ حَاسِدٍ إِذَا حَسَدَ" }, - "azkarList4": "بِسۡمِ ٱللَّهِ ٱلرَّحۡمَٰنِ ٱلرَّحِيمِ قُلۡ هُوَ ٱللَّهُ أَحَدٌ ، ٱللَّهُ ٱلصَّمَدُ ، لَمۡ يَلِدۡ وَلَمۡ يُولَدۡ ، وَلَمۡ يَكُن لَّهُۥ كُفُوًا أَحَدُۢ", + "azkarList4": "", "@azkarList4": { "description": "بِسۡمِ ٱللَّهِ ٱلرَّحۡمَٰنِ ٱلرَّحِيمِ قُلۡ هُوَ ٱللَّهُ أَحَدٌ ، ٱللَّهُ ٱلصَّمَدُ ، لَمۡ يَلِدۡ وَلَمۡ يُولَدۡ ، وَلَمۡ يَكُن لَّهُۥ كُفُوًا أَحَدُۢ" }, - "azkarList5": "ٱللَّهُ لَآ إِلَٰهَ إِلَّا هُوَ ٱلۡحَيُّ ٱلۡقَيُّومُۚ لَا تَأۡخُذُهُۥ سِنَةٞ وَلَا نَوۡمٞۚ لَّهُۥ مَا فِي ٱلسَّمَٰوَٰتِ وَمَا فِي ٱلۡأَرۡضِۗ مَن ذَا ٱلَّذِي يَشۡفَعُ عِندَهُۥٓ إِلَّا بِإِذۡنِهِۦۚ يَعۡلَمُ مَا بَيۡنَ أَيۡدِيهِمۡ وَمَا خَلۡفَهُمۡۖ وَلَا يُحِيطُونَ بِشَيۡءٖ مِّنۡ عِلۡمِهِۦٓ إِلَّا بِمَا شَآءَۚ وَسِعَ كُرۡسِيُّهُ ٱلسَّمَٰوَٰتِ وَٱلۡأَرۡضَۖ وَلَا يَ‍ُٔودُهُۥ حِفۡظُهُمَاۚ وَهُوَ ٱلۡعَلِيُّ ٱلۡعَظِيمُ", + "azkarList5": "", "@azkarList5": { "description": "ٱللَّهُ لَآ إِلَٰهَ إِلَّا هُوَ ٱلۡحَيُّ ٱلۡقَيُّومُۚ لَا تَأۡخُذُهُۥ سِنَةٞ وَلَا نَوۡمٞۚ لَّهُۥ مَا فِي ٱلسَّمَٰوَٰتِ وَمَا فِي ٱلۡأَرۡضِۗ مَن ذَا ٱلَّذِي يَشۡفَعُ عِندَهُۥٓ إِلَّا بِإِذۡنِهِۦۚ يَعۡلَمُ مَا بَيۡنَ أَيۡدِيهِمۡ وَمَا خَلۡفَهُمۡۖ وَلَا يُحِيطُونَ بِشَيۡءٖ مِّنۡ عِلۡمِهِۦٓ إِلَّا بِمَا شَآءَۚ وَسِعَ كُرۡسِيُّهُ ٱلسَّمَٰوَٰتِ وَٱلۡأَرۡضَۖ وَلَا يَ‍ُٔودُهُۥ حِفۡظُهُمَاۚ وَهُوَ ٱلۡعَلِيُّ ٱلۡعَظِيمُ" }, @@ -128,7 +128,7 @@ "safar": "صفر", "rabiAlawwal": "ربيع الأول", "rabiAlthani": "ربيع الثاني", - "jumadaAlula": "جماد الأول", + "jumadaAlula": "جمادى الأولى", "jumadaAlakhirah": "جمادة الآخرة", "rajab": "رجب", "shaban": "شعبان", @@ -168,7 +168,7 @@ "announcementOnlyMode": "وضع الإعلانات", "normalMode": "الوضع العادي", "announcementOnlyModeEXPLINATION": "اختر إذا كنت تود أن تعرض شاشة الإعلانات طوال الوقت، هذا يمكن أن يكون مفيداً إذا قمت بتثبيت الشاشة على سبيل المثال في المدخل.", - "duaaElEftarText": "اللهُمَّ إِنِّي لَكَ صُمْتُ وَعَلَى رِزْقِكَ أَفْطَرْتُ، وَإِلَيْكَ انْبَتُّ، وَعَلَيْكَ تَوَكَّلْتُ، ذَهَبَ الظَّمَأُ وَابْتلّت الْعُرُوِقُ، وَثَبَتَ الْأَجْرُ إِنْ شَاءَ اللَّهُ.", + "duaaElEftarText": "", "@duaaElEftarText": { "description": "اللهم اني لگ صمت وعلى رزقك افطرت واليك انبت وعليگ توكلت ذهب الظما وابتلت العروق وثبت الاجر انشاء الله" }, @@ -243,8 +243,8 @@ "screenLockMode": "وضع تشغيل/إيقاف الشاشة", "screenLockDesc": "تشغيل/إيقاف الشاشة قبل وبعد كل صلاة لتوفير الطاقة", "screenLockDesc2": "هذه ميزة تشغيل/إيقاف الشاشة قبل وبعد كل صلاة أذان", - "before": "دقائق قبل كل وقت للصلاة", - "after": "دقائق بعد كل وقت للصلاة", + "before": "الدقائق قبل كل صلاة", + "after": "الدقائق بعد كل صلاة", "updateAvailable": "التحديث متاح", "seeMore": "مشاهدة المزيد", "whatIsNew": "ما الجديد", @@ -290,6 +290,20 @@ } } }, + "quranReadingPagePortrait": "الصفحة {currentPage} / {totalPages}", + "@quranReadingPagePortrait": { + "description": "Placeholder text for displaying Quran reading page portrait numbers", + "placeholders": { + "currentPage": { + "type": "int", + "example": "1" + }, + "totalPages": { + "type": "int", + "example": "604" + } + } + }, "chooseQuranPage": "اختر الصفحة", "checkingForUpdates": "التحقق من وجود تحديث...", "chooseQuranType": "إختر الرواية", @@ -323,36 +337,22 @@ }, "noReciterSearchResult": "لم يتم العثور على نتائج لبحثك", "searchForReciter": "ابحث عن قارئ", - "downloadAllSuwarSuccessfully": "تم تحميل القرآن بالكامل", + "downloadAllSuwarSuccessfully": "تم تحميل القرآن كاملاً", "noSuwarDownload": "لا يوجد سور لتحميلها", - "connectDownloadQuran": "الرجاء الاتصال بالإنترنت لتنزيل القرآن", - "playInOnlineModeQuran": "الرجاء الاتصال بالإنترنت لتشغيل القرآن", + "connectDownloadQuran": "الرجاء الاتصال بالإنترنت للتنزيل", + "playInOnlineModeQuran": "الرجاء الاتصال بالإنترنت للتشغيل", "downloaded": "تم التحميل", "switchQuranType": "انتقل إلى {name}", "@switchQuranType": { - "description": "رسالة تظهر عند إضافة قارئ إلى المفضلة", + "description": "Message shown when a reciter is added to favorites", "placeholders": { "name": { "type": "String", - "example": "ورش" + "example": "Warsh" } } }, "surahSelector": "اختر السورة", - "quranReadingPagePortrait": "الصفحة {currentPage} / {totalPages}", - "@quranReadingPagePortrait": { - "description": "Placeholder text for displaying Quran reading page portrait numbers", - "placeholders": { - "currentPage": { - "type": "int", - "example": "1" - }, - "totalPages": { - "type": "int", - "example": "604" - } - } - }, "checkForUpdates": "التحقق من التحديثات", "checkForNewVersion": "تحقق مما إذا كانت هناك نسخة جديدة متوفرة", "wouldYouLikeToUpdate": "هل ترغب في تحديث التطبيق؟", @@ -362,7 +362,7 @@ "updateCancelled": "تم إلغاء التحديث", "checkingUpdates": "جارٍ التحقق من التحديثات...", "downloadingUpdate": "جارٍ تنزيل التحديث...", - "installingUpdate": "جارٍ تثبيت التحديث...", + "installingUpdate": "جارٍ تنزيل التحديث...", "updateCompletedSuccessfully": "تم التحديث بنجاح", "updateFailed": "فشل التحديث", "checkInternetUpdate": "يجب عليك الاتصال بالإنترنت للتحقق من وجود تحديثات جديدة", @@ -380,4 +380,4 @@ } } } -} +} \ No newline at end of file diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 51c34c6a4..bf9130cd8 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -335,11 +335,11 @@ "@noFavoriteReciters": { "description": "Message shown when there are no favorite reciters" }, - "noReciterSearchResult": "No results found for your search", - "searchForReciter": "Search for a reciter", + "noReciterSearchResult": "No results found for your search", + "searchForReciter": "Search for a reciter", "downloadAllSuwarSuccessfully": "The whole quran is downloaded", "noSuwarDownload": "No new suwars to download", - "connectDownloadQuran":"Please connect to Internet to download", + "connectDownloadQuran": "Please connect to Internet to download", "playInOnlineModeQuran": "Please connect to internet to play", "downloaded": "Downloaded", "switchQuranType": "Go to {name}", @@ -352,7 +352,7 @@ } } }, - "surahSelector":"Select Surah", + "surahSelector": "Select Surah", "checkForUpdates": "Check for Updates", "checkForNewVersion": "Check if a new version is available", "wouldYouLikeToUpdate": "Would you like to update the app?", @@ -380,6 +380,5 @@ } } } - - + } diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index 2bce6e640..b565369e0 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -308,7 +308,7 @@ "checkingForUpdates": "Vérification des mises à jour...", "chooseQuranType": "Choisir quran", "hafs": "Hafs", - "warsh": "Guerrier", + "warsh": "Warch", "favorites": "Favoris", "allReciters": "Tous les Réciteurs", "reciterAddedToFavorites": "Le réciteur {name} a été ajouté aux favoris", diff --git a/lib/l10n/intl_pt.arb b/lib/l10n/intl_pt.arb index 8ca4a1d94..92f2df2e5 100644 --- a/lib/l10n/intl_pt.arb +++ b/lib/l10n/intl_pt.arb @@ -20,9 +20,9 @@ "darkMode": "Modo escuro", "lightMode": "Modo claro", "changeMosque": "Alterar Mesquita", - "in1": "em", + "in1": "depois", "sec": "Seg", - "online": "On-line", + "online": "Disponível", "missingMosqueId": "MAWAQIT #ID ou MOSQUE #ID em falta", "mosqueIdIsNotValid": "{mosqueId} não é um ID de Mesquita válido", "selectMosqueId": "Por favor, insira o ID da Mesquita", @@ -68,15 +68,15 @@ "@azkarList1": { "description": "سُـبْحانَ اللهِ، والحَمْـدُ لله، واللهُ أكْـبَر 33 مرة لا إِلَٰهَ إلاّ اللّهُ وَحْـدَهُ لا شريكَ لهُ، لهُ الملكُ ولهُ الحَمْد، وهُوَ على كُلّ شَيءٍ قَـدير" }, - "azkarList2": "Em nome de Deus, o Clemente, o Misericordioso 1. Diz: «Procuro refúgio no Senhor dos humanos, 2. O Rei dos humanos, 3. O Deus dos humanos, 4. Contra o mal do murmurador que recua, 5. Que murmura nos peitos dos humanos, 6. dos jinns ou dos humanos.»", + "azkarList2": "", "@azkarList2": { "description": "بِسۡمِ ٱللَّهِ ٱلرَّحۡمَٰنِ ٱلرَّحِيمِ قُلۡ أَعُوذُ بِرَبِّ ٱلنَّاسِ ، مَلِكِ ٱلنَّاسِ ، إِلَٰهِ ٱلنَّاسِ ، مِن شَرِّ ٱلۡوَسۡوَاسِ ٱلۡخَنَّاسِ ، ٱلَّذِي يُوَسۡوِسُ فِي صُدُورِ ٱلنَّاسِ ، مِنَ ٱلۡجِنَّةِ وَٱلنَّاس" }, - "azkarList3": "Em nome de Deus, o Clemente, o Misericordioso 1. Diz: «Procuro refúgio no Senhor da manhã, 2 Contra o mal que criou, 3. E contra o mal da escuridão quando entra, 4. E contra o mal das que sopram nos nós, 5. E contra o mal do invejoso quando inveja.»", + "azkarList3": "", "@azkarList3": { "description": "بِسۡمِ ٱللَّهِ ٱلرَّحۡمَٰنِ ٱلرَّحِيمِقُلۡ أَعُوذُ بِرَبِّ ٱلۡفَلَقِ ، مِن شَرِّ مَا خَلَقَ ، وَمِن شَرِّ غَاسِقٍ إِذَا وَقَبَ ، وَمِن شَرِ ٱلنَّفَّٰثَٰتِ فِي ٱلۡعُقَدِ ، وَمِن شَرِّ حَاسِدٍ إِذَا حَسَدَ" }, - "azkarList4": "Em nome de Deus, o Clemente, o Misericordioso 1. Diz: «Ele é Allah, o Único! 2 Allah é o Independente; 3. Não gerou e nem foi gerado; 4. E não há ninguém igual a Ele.»", + "azkarList4": "", "@azkarList4": { "description": "بِسۡمِ ٱللَّهِ ٱلرَّحۡمَٰنِ ٱلرَّحِيمِ قُلۡ هُوَ ٱللَّهُ أَحَدٌ ، ٱللَّهُ ٱلصَّمَدُ ، لَمۡ يَلِدۡ وَلَمۡ يُولَدۡ ، وَلَمۡ يَكُن لَّهُۥ كُفُوًا أَحَدُۢ" }, @@ -128,7 +128,7 @@ "safar": "Safar", "rabiAlawwal": "Rabi al-Awwal", "rabiAlthani": "Rabi al-Thani", - "jumadaAlula": "Jumada al-Ula", + "jumadaAlula": "Jumada al-Awwal", "jumadaAlakhirah": "Jumada al-Thaniyah", "rajab": "Rajab", "shaban": "Sha'aban", @@ -168,7 +168,7 @@ "announcementOnlyMode": "Modo de anúncios", "normalMode": "Modo normal ", "announcementOnlyModeEXPLINATION": "Escolha se pretende que o ecrã mostre apenas anúncios, isso pode ser útil se você instalar o ecrã na entrada, por exemplo.", - "duaaElEftarText": "Ó Allah, por Ti jejuei, com o Teu sustento quebrei o jejum, em Ti acreditei e em Ti confiei. A sede foi saciada, as veias foram molhadas e a recompensa está garantida, se Deus quiser.", + "duaaElEftarText": "", "@duaaElEftarText": { "description": "اللهم اني لگ صمت وعلى رزقك افطرت واليك انبت وعليگ توكلت ذهب الظما وابتلت العروق وثبت الاجر انشاء الله" }, @@ -290,6 +290,20 @@ } } }, + "quranReadingPagePortrait": "Página {currentPage} / {totalPages}", + "@quranReadingPagePortrait": { + "description": "Placeholder text for displaying Quran reading page portrait numbers", + "placeholders": { + "currentPage": { + "type": "int", + "example": "1" + }, + "totalPages": { + "type": "int", + "example": "604" + } + } + }, "chooseQuranPage": "Escolha a página", "checkingForUpdates": "A verificar atualizações...", "chooseQuranType": "Escolher Alcorão", @@ -320,5 +334,35 @@ "noFavoriteReciters": "Sem recitadores favoritos. Tente adicionar um à lista.", "@noFavoriteReciters": { "description": "Message shown when there are no favorite reciters" - } + }, + "noReciterSearchResult": "Nenhum resultado encontrado para a sua pesquisa", + "searchForReciter": "Pesquisar por um recitador", + "downloadAllSuwarSuccessfully": "O Alcorão completo foi descarregado", + "noSuwarDownload": "Não há novos surah para descarregar", + "connectDownloadQuran": "Por favor, conecte-se à Internet para descarregar", + "playInOnlineModeQuran": "Por favor, conecte-se à internet para reproduzir", + "downloaded": "Descarregado", + "switchQuranType": "Ir para {name}", + "@switchQuranType": { + "description": "Message shown when a reciter is added to favorites", + "placeholders": { + "name": { + "type": "String", + "example": "Warsh" + } + } + }, + "surahSelector": "Selecionar Surah", + "checkForUpdates": "Verificar Atualizações", + "checkForNewVersion": "Verificar se uma nova versão está disponível", + "wouldYouLikeToUpdate": "Gostaria de atualizar a aplicação?", + "updateCompleted": "Atualização concluída com sucesso!", + "noUpdates": "Sem Atualizações", + "usingLatestVersion": "Está a utilizar a versão mais recente.", + "updateCancelled": "Atualização cancelada", + "checkingUpdates": "A verificar atualizações...", + "downloadingUpdate": "A descarregar a atualização...", + "installingUpdate": "A instalar a atualização...", + "updateCompletedSuccessfully": "Atualização concluída com sucesso", + "updateFailed": "Falha na atualização" } \ No newline at end of file