From 754f752d6248dd49aa822fd227167076d993487a Mon Sep 17 00:00:00 2001 From: Christian Meis Date: Mon, 28 Nov 2022 15:31:48 +0000 Subject: [PATCH 01/26] Translated using Weblate (German) Currently translated at 100.0% (318 of 318 strings) Translation: ntfy/Android app Translate-URL: https://hosted.weblate.org/projects/ntfy/android/de/ --- app/src/main/res/values-de/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 029f961..2d4f08c 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -327,4 +327,5 @@ Themen-URL Über In Zwischenablage kopiert + Spenden 💸 \ No newline at end of file From 47aa6e834de3264aaa2140841e1bc50f26f88108 Mon Sep 17 00:00:00 2001 From: 109247019824 Date: Sun, 27 Nov 2022 06:58:44 +0000 Subject: [PATCH 02/26] Translated using Weblate (Bulgarian) Currently translated at 100.0% (318 of 318 strings) Translation: ntfy/Android app Translate-URL: https://hosted.weblate.org/projects/ntfy/android/bg/ --- app/src/main/res/values-bg/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index 197ea54..fc6777e 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -327,4 +327,5 @@ Относно Адрес на темата Копирано в междинната памет + Даряване 💸 \ No newline at end of file From 3c0819df585f5c87e542aff9deba22fe3a09279b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuz=20Ersen?= Date: Sun, 27 Nov 2022 06:02:17 +0000 Subject: [PATCH 03/26] Translated using Weblate (Turkish) Currently translated at 100.0% (318 of 318 strings) Translation: ntfy/Android app Translate-URL: https://hosted.weblate.org/projects/ntfy/android/tr/ --- app/src/main/res/values-tr/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index dbf2453..393ec47 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -327,4 +327,5 @@ Hakkında Konu URL\'si Panoya kopyalandı + Bağış yap 💸 \ No newline at end of file From 4f0db74455b07126a8597d2c588840e18678a8b2 Mon Sep 17 00:00:00 2001 From: Eric Date: Sun, 27 Nov 2022 02:09:58 +0000 Subject: [PATCH 04/26] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (318 of 318 strings) Translation: ntfy/Android app Translate-URL: https://hosted.weblate.org/projects/ntfy/android/zh_Hans/ --- app/src/main/res/values-zh-rCN/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index f6efd9c..c0012bc 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -327,4 +327,5 @@ 关于 话题 URL 已复制到剪贴板 + 捐赠 💸 \ No newline at end of file From f5860d057c6ebbff411b78d63ed3abce394cd201 Mon Sep 17 00:00:00 2001 From: Linerly Date: Sun, 27 Nov 2022 02:08:12 +0000 Subject: [PATCH 05/26] Translated using Weblate (Indonesian) Currently translated at 100.0% (318 of 318 strings) Translation: ntfy/Android app Translate-URL: https://hosted.weblate.org/projects/ntfy/android/id/ --- app/src/main/res/values-in/strings.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 4e2b23c..fda4855 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -6,7 +6,7 @@ Notifikasi (prioritas min) Notifikasi (prioritas rendah) Layanan Langganan - Mendengarkan untuk notifikasi masuk + Mendengarkan notifikasi masuk Berlangganan ke topik pengiriman instan Berlangganan ke satu topik pengiriman instan Berlangganan ke dua topik pengiriman instan @@ -23,7 +23,7 @@ Notifikasi dibisukan Notifikasi dibisukan sampai %1$s Pengaturan - Laporkan sebuah bug + Laporkan kutu Baca dokumentasi Beri nilai aplikasi ⭐ Batalkan langganan @@ -327,4 +327,5 @@ Disalin ke papan klip Tentang URL Topik + Donasi 💸 \ No newline at end of file From 3c3f3b521d108e972b8efd14f32fa6950aadb0eb Mon Sep 17 00:00:00 2001 From: Shoshin Akamine Date: Tue, 29 Nov 2022 06:57:14 +0000 Subject: [PATCH 06/26] Translated using Weblate (Japanese) Currently translated at 100.0% (318 of 318 strings) Translation: ntfy/Android app Translate-URL: https://hosted.weblate.org/projects/ntfy/android/ja/ --- app/src/main/res/values-ja/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 0731eb9..6d05912 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -327,4 +327,5 @@ About トピックのURL クリップボードにコピーしました + 寄付する💸 \ No newline at end of file From e5059b0e494612aecc744691a71b77d2da7f951a Mon Sep 17 00:00:00 2001 From: waclaw66 Date: Sun, 27 Nov 2022 18:17:20 +0000 Subject: [PATCH 07/26] Translated using Weblate (Czech) Currently translated at 100.0% (318 of 318 strings) Translation: ntfy/Android app Translate-URL: https://hosted.weblate.org/projects/ntfy/android/cs/ --- app/src/main/res/values-cs/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 646024f..d44c7f0 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -327,4 +327,5 @@ Povolit nyní WebSockets jsou doporučenou metodou připojení k vašemu serveru, která může zlepšit zvýšit výdrž baterie, ale může vyžadovat další konfiguraci v proxy serveru. Metodu připojení lze přepnout v Nastavení. Zvolit URL služby + Přispět 💸 \ No newline at end of file From 7a7cf9d511e22248d04a9c73f7f31316700a66d5 Mon Sep 17 00:00:00 2001 From: omer s Date: Sun, 27 Nov 2022 07:12:26 +0000 Subject: [PATCH 08/26] Translated using Weblate (Hebrew) Currently translated at 15.0% (48 of 318 strings) Translation: ntfy/Android app Translate-URL: https://hosted.weblate.org/projects/ntfy/android/he/ --- app/src/main/res/values-iw/strings.xml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index 8fb0788..dabff91 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -15,7 +15,7 @@ מחק/י לצמיתות ביטול התראת %1$d - התראות %1$d + %1$d התראות אתמול הוספת רישום נראה שלא נרשמת לאף נושא עדיין. @@ -39,4 +39,20 @@ מתחבר מחדש… לחצ\\י על + על מנת ליצור או להירשם אל מול נושא מסוים. לאחר מכן תקבל\\י התראות במכשירך כשתשלח\\י התראות דרך PUT או POST. הוראות מפורטות זמינות ב-ntfy.sh, ובדוקומנטציה. - + תרום 💸 + רשום לשני נושאים במשלוח מהיר + רשום לשלושה נושאים במשלוח מהיר + רשום לנושאים במשלוח מהיר + רשום לנושא אחד במשלוח מהיר + רשום לארבעה נושאים במשלוח מהיר + רשום לחמישה נושאים במשלוח מהיר + רשום לשישה נושאים במשלוח מהיר + רשום ל%1$d נושאים במשלוח מהיר + רשום לנושאים + רשום לנושא אחד + רשום לשני נושאים + רשום לשלושה נושאים + רשום לארבעה נושאים + רשום לחמישה נושאים + רשום לשישה נושאים + \ No newline at end of file From 6f0597f8c720b500750d12ae3abe2c26df925c7c Mon Sep 17 00:00:00 2001 From: popinha13 Date: Wed, 30 Nov 2022 13:07:38 +0000 Subject: [PATCH 09/26] Translated using Weblate (Portuguese) Currently translated at 100.0% (318 of 318 strings) Translation: ntfy/Android app Translate-URL: https://hosted.weblate.org/projects/ntfy/android/pt/ --- app/src/main/res/values-pt/strings.xml | 72 +++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index bc95a63..10983c4 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -77,7 +77,7 @@ Tags: %1$s Notificação deletada Desfazer - Fazer download do arquivo + Baixar arquivo Cancelar o download Não foi possível abrir o anexo: %1$s Não foi possível abrir o anexo: O arquivo pode ter sido deletado, ou não existe app instalado que consiga abrir o arquivo. @@ -258,4 +258,74 @@ Modo claro Modo escuro Usar o padrão do sistema + Doar 💸 + Recuperação falhou %1$s + Avançado + Messagens de broadcast + Os aplicativos não podem receber notificações por broadcast + Os aplicativos já podem receber notificações por broadcast + Copiar para área de transferência + Copiar para área de transferência (censurado) + Carregar e copiar link + Carregando logs … + Logs enviados e URL copiada + Use um stream de JSON através de HTTP para se conectar ao servidor. Este método foi testado na pratica, mas pode consumir mais bateria. + ntfy %1$s (%2$s) + As notificações são entregues utilizando o Firebase. A entrega pode atrasar, mas consome menos bateria. + Aparência + Ícone de assinatura + Defina um ícone para ser exibido nas notificações + Ícone de assinatura (toque para remover) + Defina um nome de exibição personalizado para esta assinatura. Deixe em branco para o padrão (%1$s). + %1$s (padrão) + Usar configuração global + usar configuração global + Sobre + URL do tópico + Copiado para a área de transferência + Adicionar usuário + Recuperar do arquivo + Importar configurações, notificações e usuários + Restauração concluída + Registros (ate 1000 registros) para o dispositivo … + Ative o log para que seja possível compartilhar mais tarde os registros para diagnostico. + Logs de registros + Copiar/carregar logs + Copie os logs para a área de transferência ou faça o upload para nopaste.net (propriedade do autor do ntfy). Hostnames e tópicos podem ser censurados, as notificações não. + Carregar e copiar link (censurado) + Logs copiado para área de transferência + Esses tópicos/hostnames foram substituídos por nomes de frutas, então você pode compartilhar o log sem se preocupar: +\n +\n%1$s +\n +\nAs senhas são retiradas e não são listadas aqui. + Não foi possível carregar os logs: %1$s + OK + Nenhum tópico/hostname foi editado. Talvez você não tenha nenhuma assinatura\? + Limpar logs + Logs excluídos + Protocolo de conexão + Exclua os logs gravados anteriormente e comece de novo + Use WebSockets para se conectar ao servidor. Este é o método recomendado, mas pode exigir configuração adicional em seu proxy. + Stream JSON através de HTTP + Sobre + Versão + Web Sockets + Entrega instantânea + As notificações são entregues instantaneamente. Requer um serviço que roda em primeiro plano e consome mais bateria. + Copiado para área de transferência + Não foi possível salvar o ícone: %1$s + Ícone exibido nas notificações deste tópico + Nome de exibição + Você pode editar o nome de usuário/senha do usuário selecionado ou excluí-lo. + URL do serviço + Editar usuário + Você pode adicionar um usuário aqui. Todos os tópicos para o servidor fornecido usarão esse usuário. + Nome do usuário + Senha + Senha (se deixada em branco não será alterada) + Cancelar + Adicionar usuário + Deletar usuário + Salvar \ No newline at end of file From f5992fc0f9e0f9c3d8a92e582238d9d79ef22892 Mon Sep 17 00:00:00 2001 From: Rogelio Dominguez Date: Thu, 1 Dec 2022 20:47:29 +0000 Subject: [PATCH 10/26] Translated using Weblate (Spanish) Currently translated at 100.0% (318 of 318 strings) Translation: ntfy/Android app Translate-URL: https://hosted.weblate.org/projects/ntfy/android/es/ --- app/src/main/res/values-es/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 436b898..56ad002 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -327,4 +327,5 @@ Borrar la URL del servicio Cambiar a WebSockets es la forma recomendada para conectarse a su servidor, y podría mejorar la vida de la batería, pero puede requerir configuración adicional en su proxy. Esto se puede cambiar en la Configuración. Habilitar ahora + Donar 💸 \ No newline at end of file From 3082319cccfa524c94e18710fead9a31e8e1478c Mon Sep 17 00:00:00 2001 From: nickexyz Date: Fri, 2 Dec 2022 08:48:01 +0000 Subject: [PATCH 11/26] Translated using Weblate (Swedish) Currently translated at 38.0% (121 of 318 strings) Translation: ntfy/Android app Translate-URL: https://hosted.weblate.org/projects/ntfy/android/sv/ --- app/src/main/res/values-sv/strings.xml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index c9e4078..24ede8f 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -99,4 +99,28 @@ Användarnamn Lösenord Kan inte skicka meddelande: Anonym publicering är inte tillåten. + Notifikation borttagen + URL kopierad till urklipp + Kopiera notifikation + Notifikation kopierad till urklipp + Kan inte öppna URL: %1$s + Rensa alla notifikationer + Skicka testnotifikation + Kopiera + Ta bort + Ta bort permanent + Avbryt + Prenumerationsinställningar + Dela + Dela + Donera 💸 + Ångra + Öppna fil + Ta bort fil + Ladda ner fil + Avbryt nedladdning + Spara fil + Kopiera URL + nedladdning misslyckad + Prenumerationsinställningar \ No newline at end of file From b91778ad7d13402edb675d1482d43d959820ab0e Mon Sep 17 00:00:00 2001 From: Philipp Heckel Date: Sun, 4 Dec 2022 23:22:55 -0500 Subject: [PATCH 12/26] Fix Firebase-only "link expired" issue --- app/src/main/java/io/heckel/ntfy/util/Util.kt | 4 ++++ app/src/play/java/io/heckel/ntfy/firebase/FirebaseService.kt | 5 +++-- fastlane/metadata/android/en-US/changelog/29.txt | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/heckel/ntfy/util/Util.kt b/app/src/main/java/io/heckel/ntfy/util/Util.kt index d987e41..d03fe92 100644 --- a/app/src/main/java/io/heckel/ntfy/util/Util.kt +++ b/app/src/main/java/io/heckel/ntfy/util/Util.kt @@ -443,6 +443,10 @@ fun String.readBitmapFromUriOrNull(context: Context): Bitmap? { } } +fun Long.nullIfZero(): Long? { + return if (this == 0L) return null else this +} + // TextWatcher that only implements the afterTextChanged method class AfterChangedTextWatcher(val afterTextChangedFn: (s: Editable?) -> Unit) : TextWatcher { override fun afterTextChanged(s: Editable?) { diff --git a/app/src/play/java/io/heckel/ntfy/firebase/FirebaseService.kt b/app/src/play/java/io/heckel/ntfy/firebase/FirebaseService.kt index 1a367ab..830b92d 100644 --- a/app/src/play/java/io/heckel/ntfy/firebase/FirebaseService.kt +++ b/app/src/play/java/io/heckel/ntfy/firebase/FirebaseService.kt @@ -14,6 +14,7 @@ import io.heckel.ntfy.msg.ApiService import io.heckel.ntfy.msg.NotificationDispatcher import io.heckel.ntfy.msg.NotificationParser import io.heckel.ntfy.service.SubscriberService +import io.heckel.ntfy.util.nullIfZero import io.heckel.ntfy.util.toPriority import io.heckel.ntfy.util.topicShortUrl import io.heckel.ntfy.work.PollWorker @@ -94,8 +95,8 @@ class FirebaseService : FirebaseMessagingService() { val encoding = data["encoding"] val attachmentName = data["attachment_name"] ?: "attachment.bin" val attachmentType = data["attachment_type"] - val attachmentSize = data["attachment_size"]?.toLongOrNull() - val attachmentExpires = data["attachment_expires"]?.toLongOrNull() + val attachmentSize = data["attachment_size"]?.toLongOrNull()?.nullIfZero() + val attachmentExpires = data["attachment_expires"]?.toLongOrNull()?.nullIfZero() val attachmentUrl = data["attachment_url"] val truncated = (data["truncated"] ?: "") == "1" if (id == null || topic == null || message == null || timestamp == null) { diff --git a/fastlane/metadata/android/en-US/changelog/29.txt b/fastlane/metadata/android/en-US/changelog/29.txt index 805d904..84dd455 100644 --- a/fastlane/metadata/android/en-US/changelog/29.txt +++ b/fastlane/metadata/android/en-US/changelog/29.txt @@ -12,6 +12,7 @@ Bug fixes + maintenance: * Fix topics do not re-subscribe to Firebase after restoring from backup (#511) * Fix crashes from large images (#474, thanks to @daedric7 for reporting) * Fix notification click opens wrong subscription (#261, thanks to @SMAW for reporting) +* Fix Firebase-only "link expired" issue (#529) * Add donate button (no ticket) Additional translations: From 5409c84c667590b482222ee6b9c36cb7a547a76c Mon Sep 17 00:00:00 2001 From: Philipp Heckel Date: Mon, 5 Dec 2022 20:24:05 -0500 Subject: [PATCH 13/26] Dynamically remove install permission via gradle --- app/build.gradle | 23 +++++++++++++++++-- app/src/main/AndroidManifest.xml | 10 +++++++- .../io/heckel/ntfy/msg/NotificationService.kt | 3 +++ .../java/io/heckel/ntfy/ui/DetailAdapter.kt | 8 ++++++- app/src/main/java/io/heckel/ntfy/util/Util.kt | 14 ++++++++++- app/src/main/res/values/strings.xml | 1 + .../en-US/changelog/{29.txt => 31.txt} | 1 + 7 files changed, 55 insertions(+), 5 deletions(-) rename fastlane/metadata/android/en-US/changelog/{29.txt => 31.txt} (93%) diff --git a/app/build.gradle b/app/build.gradle index d34de50..2f42134 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -14,8 +14,8 @@ android { minSdkVersion 21 targetSdkVersion 33 - versionCode 29 - versionName "1.15.0" + versionCode 31 + versionName "1.15.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -44,10 +44,12 @@ android { play { buildConfigField 'boolean', 'FIREBASE_AVAILABLE', 'true' buildConfigField 'boolean', 'RATE_APP_AVAILABLE', 'true' + buildConfigField 'boolean', 'INSTALL_PACKAGES_AVAILABLE', 'false' } fdroid { buildConfigField 'boolean', 'FIREBASE_AVAILABLE', 'false' buildConfigField 'boolean', 'RATE_APP_AVAILABLE', 'false' + buildConfigField 'boolean', 'INSTALL_PACKAGES_AVAILABLE', 'true' } } @@ -64,12 +66,29 @@ android { } } +// Disables GoogleServices tasks for F-Droid variant android.applicationVariants.all { variant -> def shouldProcessGoogleServices = variant.flavorName == "play" def googleTask = tasks.findByName("process${variant.name.capitalize()}GoogleServices") googleTask.enabled = shouldProcessGoogleServices } +// Strips out REQUEST_INSTALL_PACKAGES permission for Google Play variant +android.applicationVariants.all { variant -> + def shouldStripInstallPermission = variant.flavorName == "play" + if (shouldStripInstallPermission) { + variant.outputs.each { output -> + def processManifest = output.getProcessManifestProvider().get() + processManifest.doLast { task -> + def outputDir = task.getMultiApkManifestOutputDirectory().get().asFile + def manifestOutFile = file("$outputDir/AndroidManifest.xml") + def newFileContents = manifestOutFile.collect { s -> s.contains("android.permission.REQUEST_INSTALL_PACKAGES") ? "" : s }.join("\n") + manifestOutFile.write(newFileContents, 'UTF-8') + } + } + } +} + dependencies { // AndroidX, The Basics implementation "androidx.appcompat:appcompat:1.5.1" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4cbdf60..0580856 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,7 @@ + @@ -8,10 +9,17 @@ - + + + Unit, private val onLongClick: (Notification) -> Unit) : ListAdapter(TopicDiffCallback) { val selected = mutableSetOf() // Notification IDs @@ -371,6 +371,12 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope: } private fun openFile(context: Context, attachment: Attachment): Boolean { + if (!canOpenAttachment(attachment)) { + Toast + .makeText(context, context.getString(R.string.detail_item_cannot_open_apk), Toast.LENGTH_LONG) + .show() + return true + } Log.d(TAG, "Opening file ${attachment.contentUri}") try { val contentUri = Uri.parse(attachment.contentUri) diff --git a/app/src/main/java/io/heckel/ntfy/util/Util.kt b/app/src/main/java/io/heckel/ntfy/util/Util.kt index d03fe92..078bf27 100644 --- a/app/src/main/java/io/heckel/ntfy/util/Util.kt +++ b/app/src/main/java/io/heckel/ntfy/util/Util.kt @@ -25,6 +25,7 @@ import android.view.Window import android.widget.ImageView import android.widget.Toast import androidx.appcompat.app.AppCompatDelegate +import io.heckel.ntfy.BuildConfig import io.heckel.ntfy.R import io.heckel.ntfy.db.* import io.heckel.ntfy.msg.MESSAGE_ENCODING_BASE64 @@ -321,6 +322,8 @@ fun formatBytes(bytes: Long, decimals: Int = 1): String { return java.lang.String.format("%.${decimals}f %cB", value / 1024.0, ci.current()) } +const val androidAppMimeType = "application/vnd.android.package-archive" + fun mimeTypeToIconResource(mimeType: String?): Int { return if (mimeType?.startsWith("image/") == true) { R.drawable.ic_file_image_red_24dp @@ -328,7 +331,7 @@ fun mimeTypeToIconResource(mimeType: String?): Int { R.drawable.ic_file_video_orange_24dp } else if (mimeType?.startsWith("audio/") == true) { R.drawable.ic_file_audio_purple_24dp - } else if (mimeType == "application/vnd.android.package-archive") { + } else if (mimeType == androidAppMimeType) { R.drawable.ic_file_app_gray_24dp } else { R.drawable.ic_file_document_blue_24dp @@ -339,6 +342,15 @@ fun supportedImage(mimeType: String?): Boolean { return listOf("image/jpeg", "image/png").contains(mimeType) } +// Google Play doesn't allow us to install received .apk files anymore. +// See https://github.com/binwiederhier/ntfy/issues/531 +fun canOpenAttachment(attachment: Attachment?): Boolean { + if (attachment?.type == androidAppMimeType && !BuildConfig.INSTALL_PACKAGES_AVAILABLE) { + return false + } + return true +} + // Check if battery optimization is enabled, see https://stackoverflow.com/a/49098293/1440785 fun isIgnoringBatteryOptimizations(context: Context): Boolean { val powerManager = context.applicationContext.getSystemService(Context.POWER_SERVICE) as PowerManager diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 59c9817..d26c9d9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -153,6 +153,7 @@ Cannot open attachment: %1$s Cannot open attachment: The file may have been deleted, or no installed app can open the file. Cannot open URL: %1$s + Apps cannot be installed anymore. Download via browser instead. See issue #531 for details. Cannot save attachment: %1$s Cannot delete attachment: %1$s Could not download attachment: %1$s diff --git a/fastlane/metadata/android/en-US/changelog/29.txt b/fastlane/metadata/android/en-US/changelog/31.txt similarity index 93% rename from fastlane/metadata/android/en-US/changelog/29.txt rename to fastlane/metadata/android/en-US/changelog/31.txt index 84dd455..c807459 100644 --- a/fastlane/metadata/android/en-US/changelog/29.txt +++ b/fastlane/metadata/android/en-US/changelog/31.txt @@ -13,6 +13,7 @@ Bug fixes + maintenance: * Fix crashes from large images (#474, thanks to @daedric7 for reporting) * Fix notification click opens wrong subscription (#261, thanks to @SMAW for reporting) * Fix Firebase-only "link expired" issue (#529) +* Remove "Install .apk" feature in Google Play variant due to policy change (#531) * Add donate button (no ticket) Additional translations: From 021bface37a1cabe11a80daa7f801fa96fcb2631 Mon Sep 17 00:00:00 2001 From: Ivan Ip Date: Sun, 4 Dec 2022 03:21:21 +0000 Subject: [PATCH 14/26] Translated using Weblate (Chinese (Traditional)) Currently translated at 57.8% (184 of 318 strings) Translation: ntfy/Android app Translate-URL: https://hosted.weblate.org/projects/ntfy/android/zh_Hant/ --- app/src/main/res/values-zh-rTW/strings.xml | 194 ++++++++++++++++----- 1 file changed, 153 insertions(+), 41 deletions(-) diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index da86ce1..c6f7aa6 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -1,23 +1,23 @@ - 已訂閱6個主題 - 通知(預設優先) - 回報bug - 監聽傳入通知 + 已訂閱 6 個主題 + 通知 (預設優先) + 問題回報 + 正在接收通知 已訂閱即時推送主題 - 已訂閱1個即時推送主題 - 已訂閱2個即時推送主題 - 已訂閱4個即時推送主題 - 已訂閱5個即時推送主題 - 已訂閱6個即時推送主題 - 已訂閱%1$d個即時推送主題 + 已訂閱 1 個即時推送主題 + 已訂閱 2 個即時推送主題 + 已訂閱 4 個即時推送主題 + 已訂閱 5 個即時推送主題 + 已訂閱 6 個即時推送主題 + 已訂閱 %1$d 個即時推送主題 已訂閱主題 - 收到%1$d個通知 + 收到 %1$d 個通知 已同步到最新 - 有%1$d個訂閱無法更新 + 有 %1$d 個訂閱無法更新 \n \n%2$s - 訂閱無法更新:%1$s + 訂閱無法更新: %1$s 已訂閱主題 通知已開啟 通知已靜音 @@ -27,8 +27,8 @@ 取消訂閱已選取的主題且永久刪除所有通知? 永久刪除 取消 - %1$d個通知 - %1$d個通知 + %1$d 個通知 + %1$d 個通知 昨天 新增訂閱 看來你還沒有訂閱任何主題。 @@ -36,7 +36,7 @@ 更多資訊請上 ntfy.sh,docs會有更多說明。 此訂閱已由 %1$s 透過 UnifiedPush 管理 %1$s (UnifiedPush) - 為了避免通知傳送問題,電池最佳化必須關閉。 + 為了避免通知傳送問題,請務必關閉電池最佳化功能。 稍後詢問我 略過 立即修正 @@ -47,35 +47,147 @@ 因為主題不能受密碼保護,請盡量取一個難以猜測的主題名稱。在訂閱之後你就可以使用 PUT/POST 來發送通知。 使用其他伺服器 在下方輸入自訂的網址來訂閱主題。 - 通知(最低優先) - 通知(低優先) - 通知(高優先) - 通知(最高優先) + 通知 (最低優先) + 通知 (低優先) + 通知 (高優先) + 通知 (最高優先) 訂閱服務 - 已訂閱3個即時推送主題 - 閱讀文件 - 建議使用 WebSockets 來連線你的伺服器,此動作可以有效增加電池續航,但需要對proxy進行更多設定。這個動作可以在設定中進行。 - 已訂閱3個主題 - 已訂閱%1$d個主題 - 已訂閱1個主題 - 已訂閱2個主題 - 已訂閱4個主題 - 已訂閱5個主題 - 重新連線中 … - 通知靜音到%1$s - 主題名稱(例如:phils_alerts) + 已訂閱 3 個即時推送主題 + 閱讀技術文件 + 建議使用 WebSocket 來接收通知。這個連接方式能有效改善電池續航,但可能需要在伺服器端進行額外設定。你可以在設定頁面更改不同的連接方式。 + 已訂閱 3 個主題 + 已訂閱 %1$d 個主題 + 已訂閱 1 個主題 + 已訂閱 2 個主題 + 已訂閱 4 個主題 + 已訂閱 5 個主題 + 重新連線中… + 通知靜音到 %1$s + 主題名稱 (例如:phils_alerts) 取消 訂閱 - 退回 - 連接失敗: %1$s + 返回 + 連接失敗: %1$s 需要登入 - 使用者名字 + 使用者名稱 密碼 - 登入失敗. 使用者%1$s 未獲得授權. - 新使用者 - 選擇服務網址 - 清除服務網址 - 複製到剪貼簿 + 登入失敗,使用者 %1$s 並未授權訂閱這個主題。 + 建立新使用者 + 選擇 ntfy 服務 URL + 清除 URL + 已複製到剪貼簿 登入 - 這篇主題要求登入. 請輸入帳號密碼. + 這個主題需要登入,請先輸入帳號密碼。 + 在省電模式下依然接收即時通知 + 確保通知能在未使用裝置時都能接收。 + 取消 + 取消 + 取消 + 分享 + 分享到 + + 預設 + + 最高 + 自動刪除 1 個月前的通知 + 1 天後 + 3 天後 + 1 週後 + 1 個月後 + 3 個月後 + 一般 + 預設伺服器 + %1$s (預設) + 管理使用者 + 備份與還原 + 已複製到剪貼簿 + 關於 + 版本號 + ntfy %1$s (%2$s) + 主題 + 即時通知 + 使用全域設定 + 新增使用者 + 捐獻 💸 + 復原 + 已下載 %1$d%% + 啓用即時通知 + 關閉即時通知 + 清除所有通知 + 複製 + 刪除 + 傳送 + 預覽 + 取消 + 儲存 + 30 分鐘 + 1 小時 + 2 小時 + 8 小時 + 直到明天 + 直到我解除為止 + 開啓 + 瀏覽 + 下載 + 取消 + %1$s +\n檔案: %2$s + 下載中 %1$s, %2$d%% +\n%3$s + %1$s +\n檔案下載已完成: %2$s + %1$s +\n檔案下載失敗: %2$s + %1$s 失敗: %2$s + 設定 + 顯示所有通知 + 分鐘 + 下載附件 + 自動下載所有附件 + 從不自動下載附件 + 自動下載小於 %1$s 的附件 + 從不自動下載 + 自動下載所有東西 + 小於 500 kB + 小於 100 kB + 小於 1 MB + 小於 5 MB + 小於 50 MB + 自動刪除通知 + 從不自動刪除通知 + 自動刪除 1 天前的通知 + 自動刪除 3 天前的通知 + 自動刪除 1 週前的通知 + 自動刪除 3 個月前的通知 + 從不 + 使用者 + 新增使用者 + 建立新使用者 + 黑暗模式 + 全部 + 僅備份設定 + 全部備份 (使用者檔案除外) + 已成功備份 + 還原成功 + 還原失敗: %1$s + 進階 + 確定 + 連接方式 + 透過 HTTP 連接伺服器來接收 JSON 串流,但可能會持續消耗較大電量。 + (建議) 透過 WebSocket 連接伺服器,但伺服器可能需要額外設定來啓用這種連接方式。 + JSON 串流 (透過 HTTP 連接) + WebSocket + 主題 URL + 已複製到剪貼簿 + 密碼 + 儲存 + 新增使用者 + 取消 + 使用者名稱 + 通知 + 發送測試訊息 + 暫停通知 + 小於 10 MB + 關於 + 備份失敗: %1$s \ No newline at end of file From 2ff7098ec1577fe4e7c2266e6c80426ed422bf68 Mon Sep 17 00:00:00 2001 From: Ivan Ip Date: Sun, 4 Dec 2022 02:43:19 +0000 Subject: [PATCH 15/26] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (3 of 3 strings) Translation: ntfy/Android app (Fastlane metadata) Translate-URL: https://hosted.weblate.org/projects/ntfy/android-fastlane/zh_Hant/ --- .../android/zh-Hant/full_description.txt | 17 +++++++++++++++++ .../android/zh-Hant/short_description.txt | 1 + fastlane/metadata/android/zh-Hant/title.txt | 1 + 3 files changed, 19 insertions(+) create mode 100644 fastlane/metadata/android/zh-Hant/full_description.txt create mode 100644 fastlane/metadata/android/zh-Hant/short_description.txt create mode 100644 fastlane/metadata/android/zh-Hant/title.txt diff --git a/fastlane/metadata/android/zh-Hant/full_description.txt b/fastlane/metadata/android/zh-Hant/full_description.txt new file mode 100644 index 0000000..50bd036 --- /dev/null +++ b/fastlane/metadata/android/zh-Hant/full_description.txt @@ -0,0 +1,17 @@ +不論 Bash 還是 PowerShell,或者是你自己的應用程式、curl 或者 Invoke-WebRequest 等等,都可以透過 HTTP PUT/POST 向你的裝置傳送通知。 + +ntfy 是 https://ntfy.sh 的 Android APP,一個打造在 HTTP 標準之上的免費開源 pub-sub 服務。你可以透過訂閱主題來接收通過 HTTP API 發送的通知。 + +當中,你可能找到千變萬化的用途,例如: +* 在一個很長很長的程序完成後通知自己 +* 在備份失敗後通知自己 +* 當有人登入到伺服器的時候發送通知 + +發送通知可以簡單如此: + +$ curl -d "備份完成了!" ntfy.sh/mytopic + +你也可以在下面的連結閱讀更多資訊: +* 網站: https://ntfy.sh +* GitHub(伺服器端): https://github.com/binwiederhier/ntfy +* GitHub(Android APP): https://github.com/binwiederhier/ntfy-android diff --git a/fastlane/metadata/android/zh-Hant/short_description.txt b/fastlane/metadata/android/zh-Hant/short_description.txt new file mode 100644 index 0000000..71f9a34 --- /dev/null +++ b/fastlane/metadata/android/zh-Hant/short_description.txt @@ -0,0 +1 @@ +透過 HTTP PUT/POST 方式傳送任何通知到你的裝置 diff --git a/fastlane/metadata/android/zh-Hant/title.txt b/fastlane/metadata/android/zh-Hant/title.txt new file mode 100644 index 0000000..80dc0ad --- /dev/null +++ b/fastlane/metadata/android/zh-Hant/title.txt @@ -0,0 +1 @@ +ntfy - PUT/POST 到你的裝置 From 6a8d222e12d20ea69a34415e974175a98693fd78 Mon Sep 17 00:00:00 2001 From: Joan Gargallo Date: Mon, 5 Dec 2022 10:37:18 +0000 Subject: [PATCH 16/26] Translated using Weblate (Catalan) Currently translated at 13.5% (43 of 318 strings) Translation: ntfy/Android app Translate-URL: https://hosted.weblate.org/projects/ntfy/android/ca/ --- app/src/main/res/values-ca/strings.xml | 39 ++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 6564bca..d70279f 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -6,4 +6,43 @@ Notificacions (alta prioritat) Notificacions (prioritat màx) Servei Subscripció + Donar 💸 + reconnectant… + Escoltant notificacions entrants + Subscrit per entrega instantània de temes + Subscrit per entrega instantània d\'un tema + Subscrit per dues entregues instantànies de temes + Subscrit per tres entregues instantànies de temes + Subscrit per quatre entregues instantànies de temes + Subscrit per cinc entregues instantànies de temes + Subscrit per sis entregues instantànies de temes + Subscrit per %1$d entregues instantànies de temes + Subscrit als temes + Subscrit a un tema + Subscrit a dos temes + Subscrit a tres temes + Subscrit a sis temes + Eliminat permanentment + Cancel·lar + %1$d notificació + Subscrit a %1$d temes + Subscrit a quatre temes + Subscrit a cinc temes + %1$d notificacions rebudes + Tot està actualitzat + No es poden actualitzar %1$d subscripciones +\n +\n%2$s + No s\'ha pogut actualitzar la subscripció: %1$s + Temes subscrits + Notificacions activades + Notificacions silenciades + Notificacions silenciades fins: %1$s + Ajustos + Reportar un problema + Llegir la documentació + Valora la aplicació ⭐ + Donar-se de baixa + Donar-se de baixa del tema(es) seleccionat(s) permanentment i eliminar totes les notificacions\? + %1$d notificacions \ No newline at end of file From e64cd79c28122596c9989563af12c59916eb27e5 Mon Sep 17 00:00:00 2001 From: Philipp Heckel Date: Tue, 6 Dec 2022 16:17:05 -0500 Subject: [PATCH 17/26] Fix Android 5 crashes on unsubscribing --- app/build.gradle | 4 +-- .../heckel/ntfy/firebase/FirebaseMessenger.kt | 1 + .../java/io/heckel/ntfy/backup/Backuper.kt | 6 ++-- .../heckel/ntfy/service/SubscriberService.kt | 10 +++---- .../java/io/heckel/ntfy/ui/DetailActivity.kt | 13 ++++---- .../java/io/heckel/ntfy/ui/MainActivity.kt | 4 +-- .../java/io/heckel/ntfy/ui/MainAdapter.kt | 2 +- .../java/io/heckel/ntfy/ui/ShareActivity.kt | 5 ++-- .../java/io/heckel/ntfy/ui/UserFragment.kt | 30 +++++-------------- app/src/main/java/io/heckel/ntfy/util/Util.kt | 25 +++++++--------- .../metadata/android/en-US/changelog/32.txt | 2 ++ 11 files changed, 43 insertions(+), 59 deletions(-) create mode 100644 fastlane/metadata/android/en-US/changelog/32.txt diff --git a/app/build.gradle b/app/build.gradle index 2f42134..b79295a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -14,8 +14,8 @@ android { minSdkVersion 21 targetSdkVersion 33 - versionCode 31 - versionName "1.15.2" + versionCode 32 + versionName "1.16.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/fdroid/java/io/heckel/ntfy/firebase/FirebaseMessenger.kt b/app/src/fdroid/java/io/heckel/ntfy/firebase/FirebaseMessenger.kt index e121d2f..d12f90e 100644 --- a/app/src/fdroid/java/io/heckel/ntfy/firebase/FirebaseMessenger.kt +++ b/app/src/fdroid/java/io/heckel/ntfy/firebase/FirebaseMessenger.kt @@ -1,5 +1,6 @@ package io.heckel.ntfy.firebase +@Suppress("UNUSED_PARAMETER") class FirebaseMessenger { fun subscribe(topic: String) { // Dummy to keep F-Droid flavor happy diff --git a/app/src/main/java/io/heckel/ntfy/backup/Backuper.kt b/app/src/main/java/io/heckel/ntfy/backup/Backuper.kt index 8c87f90..5dbbab5 100644 --- a/app/src/main/java/io/heckel/ntfy/backup/Backuper.kt +++ b/app/src/main/java/io/heckel/ntfy/backup/Backuper.kt @@ -89,7 +89,7 @@ class Backuper(val context: Context) { private suspend fun applySubscriptions(subscriptions: List?) { if (subscriptions == null) { - return; + return } val appBaseUrl = context.getString(R.string.app_base_url) subscriptions.forEach { s -> @@ -119,7 +119,7 @@ class Backuper(val context: Context) { private suspend fun applyNotifications(notifications: List?) { if (notifications == null) { - return; + return } notifications.forEach { n -> try { @@ -188,7 +188,7 @@ class Backuper(val context: Context) { private suspend fun applyUsers(users: List?) { if (users == null) { - return; + return } users.forEach { u -> try { diff --git a/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt b/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt index 103ff1c..8577973 100644 --- a/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt +++ b/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt @@ -310,11 +310,11 @@ class SubscriberService : Service() { override fun onTaskRemoved(rootIntent: Intent) { val restartServiceIntent = Intent(applicationContext, SubscriberService::class.java).also { it.setPackage(packageName) - }; - val restartServicePendingIntent: PendingIntent = PendingIntent.getService(this, 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE); - applicationContext.getSystemService(Context.ALARM_SERVICE); - val alarmService: AlarmManager = applicationContext.getSystemService(Context.ALARM_SERVICE) as AlarmManager; - alarmService.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + 1000, restartServicePendingIntent); + } + val restartServicePendingIntent: PendingIntent = PendingIntent.getService(this, 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE) + applicationContext.getSystemService(Context.ALARM_SERVICE) + val alarmService: AlarmManager = applicationContext.getSystemService(Context.ALARM_SERVICE) as AlarmManager + alarmService.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + 1000, restartServicePendingIntent) } /* This re-starts the service on reboot; see manifest */ diff --git a/app/src/main/java/io/heckel/ntfy/ui/DetailActivity.kt b/app/src/main/java/io/heckel/ntfy/ui/DetailActivity.kt index 4fc9ec7..08ba821 100644 --- a/app/src/main/java/io/heckel/ntfy/ui/DetailActivity.kt +++ b/app/src/main/java/io/heckel/ntfy/ui/DetailActivity.kt @@ -7,6 +7,7 @@ import android.content.Context import android.content.Intent import android.content.Intent.ACTION_VIEW import android.net.Uri +import android.os.Build import android.os.Bundle import android.text.Html import android.view.ActionMode @@ -178,7 +179,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra howToExample.linksClickable = true val howToText = getString(R.string.detail_how_to_example, topicUrl) - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { howToExample.text = Html.fromHtml(howToText, Html.FROM_HTML_MODE_LEGACY) } else { howToExample.text = Html.fromHtml(howToText) @@ -241,7 +242,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { override fun onItemRangeInserted(positionStart: Int, itemCount: Int) { if (positionStart == 0) { - Log.d(TAG, "$itemCount item(s) inserted at $positionStart, scrolling to the top") + Log.d(TAG, "$itemCount item(s) inserted at 0, scrolling to the top") mainList.scrollToPosition(positionStart) } } @@ -571,7 +572,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra dialog.setOnShowListener { dialog .getButton(AlertDialog.BUTTON_POSITIVE) - .setTextAppearance(R.style.DangerText) + .dangerButton(this) } dialog.show() } @@ -609,7 +610,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra dialog.setOnShowListener { dialog .getButton(AlertDialog.BUTTON_POSITIVE) - .setTextAppearance(R.style.DangerText) + .dangerButton(this) } dialog.show() } @@ -619,7 +620,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra handleActionModeClick(notification) } else if (notification.click != "") { try { - startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(notification.click))) + startActivity(Intent(ACTION_VIEW, Uri.parse(notification.click))) } catch (e: Exception) { Log.w(TAG, "Cannot open click URL", e) runOnUiThread { @@ -720,7 +721,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra dialog.setOnShowListener { dialog .getButton(AlertDialog.BUTTON_POSITIVE) - .setTextAppearance(R.style.DangerText) + .dangerButton(this) } dialog.show() } diff --git a/app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt b/app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt index ad928a4..2137e8c 100644 --- a/app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt +++ b/app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt @@ -35,7 +35,6 @@ import io.heckel.ntfy.app.Application import io.heckel.ntfy.db.Repository import io.heckel.ntfy.db.Subscription import io.heckel.ntfy.firebase.FirebaseMessenger -import io.heckel.ntfy.util.Log import io.heckel.ntfy.msg.ApiService import io.heckel.ntfy.msg.DownloadManager import io.heckel.ntfy.msg.DownloadType @@ -48,7 +47,6 @@ import io.heckel.ntfy.work.PollWorker import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch -import java.security.SecureRandom import java.util.* import java.util.concurrent.TimeUnit import kotlin.random.Random @@ -622,7 +620,7 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc dialog.setOnShowListener { dialog .getButton(AlertDialog.BUTTON_POSITIVE) - .setTextAppearance(R.style.DangerText) + .dangerButton(this) } dialog.show() } diff --git a/app/src/main/java/io/heckel/ntfy/ui/MainAdapter.kt b/app/src/main/java/io/heckel/ntfy/ui/MainAdapter.kt index bb78468..4d95d0e 100644 --- a/app/src/main/java/io/heckel/ntfy/ui/MainAdapter.kt +++ b/app/src/main/java/io/heckel/ntfy/ui/MainAdapter.kt @@ -119,7 +119,7 @@ class MainAdapter(private val repository: Repository, private val onClick: (Subs if (selected.contains(subscription.id)) { itemView.setBackgroundResource(Colors.itemSelectedBackground(context)) } else { - itemView.setBackgroundColor(Color.TRANSPARENT); + itemView.setBackgroundColor(Color.TRANSPARENT) } } } diff --git a/app/src/main/java/io/heckel/ntfy/ui/ShareActivity.kt b/app/src/main/java/io/heckel/ntfy/ui/ShareActivity.kt index 1db1c33..984f6af 100644 --- a/app/src/main/java/io/heckel/ntfy/ui/ShareActivity.kt +++ b/app/src/main/java/io/heckel/ntfy/ui/ShareActivity.kt @@ -1,7 +1,6 @@ package io.heckel.ntfy.ui import android.content.Intent -import android.graphics.BitmapFactory import android.net.Uri import android.os.Bundle import android.os.Parcelable @@ -295,7 +294,7 @@ class ShareActivity : AppCompatActivity() { .show() } } catch (e: Exception) { - val message = if (e is ApiService.UnauthorizedException) { + val errorMessage = if (e is ApiService.UnauthorizedException) { if (e.user != null) { getString(R.string.detail_test_message_error_unauthorized_user, e.user.username) } else { @@ -308,7 +307,7 @@ class ShareActivity : AppCompatActivity() { } runOnUiThread { progress.visibility = View.GONE - errorText.text = message + errorText.text = errorMessage errorImage.visibility = View.VISIBLE errorText.visibility = View.VISIBLE } diff --git a/app/src/main/java/io/heckel/ntfy/ui/UserFragment.kt b/app/src/main/java/io/heckel/ntfy/ui/UserFragment.kt index 7dd8bb9..d4a7097 100644 --- a/app/src/main/java/io/heckel/ntfy/ui/UserFragment.kt +++ b/app/src/main/java/io/heckel/ntfy/ui/UserFragment.kt @@ -5,8 +5,6 @@ import android.app.Dialog import android.content.Context import android.os.Build import android.os.Bundle -import android.text.Editable -import android.text.TextWatcher import android.view.View import android.view.WindowManager import android.widget.Button @@ -16,6 +14,8 @@ import androidx.fragment.app.DialogFragment import com.google.android.material.textfield.TextInputEditText import io.heckel.ntfy.R import io.heckel.ntfy.db.User +import io.heckel.ntfy.util.AfterChangedTextWatcher +import io.heckel.ntfy.util.dangerButton import io.heckel.ntfy.util.validUrl class UserFragment : DialogFragment() { @@ -98,28 +98,14 @@ class UserFragment : DialogFragment() { // Delete button should be red if (user != null) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - dialog - .getButton(AlertDialog.BUTTON_NEUTRAL) - .setTextAppearance(R.style.DangerText) - } else { - dialog - .getButton(AlertDialog.BUTTON_NEUTRAL) - .setTextColor(ContextCompat.getColor(requireContext(), Colors.dangerText(requireContext()))) - } + dialog + .getButton(AlertDialog.BUTTON_NEUTRAL) + .dangerButton(requireContext()) } // Validate input when typing - val textWatcher = object : TextWatcher { - override fun afterTextChanged(s: Editable?) { - validateInput() - } - override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { - // Nothing - } - override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { - // Nothing - } + val textWatcher = AfterChangedTextWatcher { + validateInput() } baseUrlView.addTextChangedListener(textWatcher) usernameView.addTextChangedListener(textWatcher) @@ -140,7 +126,7 @@ class UserFragment : DialogFragment() { } // Show keyboard when the dialog is shown (see https://stackoverflow.com/a/19573049/1440785) - dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); + dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE) return dialog } diff --git a/app/src/main/java/io/heckel/ntfy/util/Util.kt b/app/src/main/java/io/heckel/ntfy/util/Util.kt index 078bf27..86c9728 100644 --- a/app/src/main/java/io/heckel/ntfy/util/Util.kt +++ b/app/src/main/java/io/heckel/ntfy/util/Util.kt @@ -22,13 +22,16 @@ import android.util.Base64 import android.util.TypedValue import android.view.View import android.view.Window +import android.widget.Button import android.widget.ImageView import android.widget.Toast import androidx.appcompat.app.AppCompatDelegate +import androidx.core.content.ContextCompat import io.heckel.ntfy.BuildConfig import io.heckel.ntfy.R import io.heckel.ntfy.db.* import io.heckel.ntfy.msg.MESSAGE_ENCODING_BASE64 +import io.heckel.ntfy.ui.Colors import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay @@ -218,16 +221,6 @@ fun maybeAppendActionErrors(message: String, notification: Notification): String } } -// Checks in the most horrible way if a content URI exists; I couldn't find a better way -fun fileExists(context: Context, contentUri: String?): Boolean { - return try { - fileStat(context, Uri.parse(contentUri)) // Throws if the file does not exist - true - } catch (_: Exception) { - false - } -} - // Queries the filename of a content URI fun fileName(context: Context, contentUri: String?, fallbackName: String): String { return try { @@ -455,10 +448,6 @@ fun String.readBitmapFromUriOrNull(context: Context): Bitmap? { } } -fun Long.nullIfZero(): Long? { - return if (this == 0L) return null else this -} - // TextWatcher that only implements the afterTextChanged method class AfterChangedTextWatcher(val afterTextChangedFn: (s: Editable?) -> Unit) : TextWatcher { override fun afterTextChanged(s: Editable?) { @@ -506,3 +495,11 @@ fun String.sha256(): String { val digest = md.digest(this.toByteArray()) return digest.fold("") { str, it -> str + "%02x".format(it) } } + +fun Button.dangerButton(context: Context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + setTextAppearance(R.style.DangerText) + } else { + setTextColor(ContextCompat.getColor(context, Colors.dangerText(context))) + } +} diff --git a/fastlane/metadata/android/en-US/changelog/32.txt b/fastlane/metadata/android/en-US/changelog/32.txt new file mode 100644 index 0000000..27617b8 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelog/32.txt @@ -0,0 +1,2 @@ +Bug fixes: +* Android 5 (SDK 21): Fix crash on unsubscribing (#528, thanks to Roger M.) From 314bba41138479ae0f7a71c12c869ac85b632931 Mon Sep 17 00:00:00 2001 From: Philipp Heckel Date: Tue, 6 Dec 2022 20:37:30 -0500 Subject: [PATCH 18/26] Some style fixes --- app/src/main/java/io/heckel/ntfy/app/Application.kt | 1 - app/src/main/java/io/heckel/ntfy/msg/ApiService.kt | 4 ++-- .../main/java/io/heckel/ntfy/msg/DownloadManager.kt | 2 +- .../java/io/heckel/ntfy/service/SubscriberService.kt | 2 +- app/src/main/java/io/heckel/ntfy/ui/AddFragment.kt | 2 -- app/src/main/java/io/heckel/ntfy/ui/DetailAdapter.kt | 12 +++++++----- .../java/io/heckel/ntfy/ui/DetailSettingsActivity.kt | 9 ++++----- app/src/main/java/io/heckel/ntfy/ui/MainAdapter.kt | 6 +----- app/src/main/java/io/heckel/ntfy/ui/MainViewModel.kt | 2 -- .../java/io/heckel/ntfy/ui/NotificationFragment.kt | 1 - app/src/main/java/io/heckel/ntfy/ui/UserFragment.kt | 2 -- .../main/java/io/heckel/ntfy/up/BroadcastReceiver.kt | 2 -- app/src/main/res/values-de/strings.xml | 6 +++--- app/src/main/res/values/strings.xml | 2 +- 14 files changed, 20 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/io/heckel/ntfy/app/Application.kt b/app/src/main/java/io/heckel/ntfy/app/Application.kt index b4b104c..6e4e760 100644 --- a/app/src/main/java/io/heckel/ntfy/app/Application.kt +++ b/app/src/main/java/io/heckel/ntfy/app/Application.kt @@ -1,7 +1,6 @@ package io.heckel.ntfy.app import android.app.Application -import android.content.Context import io.heckel.ntfy.db.Database import io.heckel.ntfy.db.Repository import io.heckel.ntfy.util.Log diff --git a/app/src/main/java/io/heckel/ntfy/msg/ApiService.kt b/app/src/main/java/io/heckel/ntfy/msg/ApiService.kt index 64baa45..bdd8b01 100644 --- a/app/src/main/java/io/heckel/ntfy/msg/ApiService.kt +++ b/app/src/main/java/io/heckel/ntfy/msg/ApiService.kt @@ -95,7 +95,7 @@ class ApiService { throw Exception("Unexpected response ${response.code} when polling topic $url") } val body = response.body?.string()?.trim() - if (body == null || body.isEmpty()) return emptyList() + if (body.isNullOrEmpty()) return emptyList() val notifications = body.lines().mapNotNull { line -> parser.parse(line, subscriptionId = subscriptionId, notificationId = 0) // No notification when we poll } @@ -166,7 +166,7 @@ class ApiService { } class UnauthorizedException(val user: User?) : Exception() - class EntityTooLargeException() : Exception() + class EntityTooLargeException : Exception() companion object { val USER_AGENT = "ntfy/${BuildConfig.VERSION_NAME} (${BuildConfig.FLAVOR}; Android ${Build.VERSION.RELEASE}; SDK ${Build.VERSION.SDK_INT})" diff --git a/app/src/main/java/io/heckel/ntfy/msg/DownloadManager.kt b/app/src/main/java/io/heckel/ntfy/msg/DownloadManager.kt index ab0dd2e..83cfb1a 100644 --- a/app/src/main/java/io/heckel/ntfy/msg/DownloadManager.kt +++ b/app/src/main/java/io/heckel/ntfy/msg/DownloadManager.kt @@ -11,7 +11,7 @@ import io.heckel.ntfy.util.Log * Download attachment in the background via WorkManager * * The indirection via WorkManager is required since this code may be executed - * in a doze state and Internet may not be available. It's also best practice apparently. + * in a doze state and Internet may not be available. It's also best practice, apparently. */ object DownloadManager { private const val TAG = "NtfyDownloadManager" diff --git a/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt b/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt index 8577973..2f59aa6 100644 --- a/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt +++ b/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt @@ -200,7 +200,7 @@ class SubscriberService : Service() { // retrieve old messages. This is important, so we don't download attachments from old messages. val since = sinceByBaseUrl[connectionId.baseUrl] ?: "none" - val serviceActive = { -> isServiceStarted } + val serviceActive = { isServiceStarted } val user = repository.getUser(connectionId.baseUrl) val connection = if (repository.getConnectionProtocol() == Repository.CONNECTION_PROTOCOL_WS) { val alarmManager = getSystemService(ALARM_SERVICE) as AlarmManager diff --git a/app/src/main/java/io/heckel/ntfy/ui/AddFragment.kt b/app/src/main/java/io/heckel/ntfy/ui/AddFragment.kt index b9770fa..8e56bab 100644 --- a/app/src/main/java/io/heckel/ntfy/ui/AddFragment.kt +++ b/app/src/main/java/io/heckel/ntfy/ui/AddFragment.kt @@ -5,8 +5,6 @@ import android.app.AlertDialog import android.app.Dialog import android.content.Context import android.os.Bundle -import android.text.Editable -import android.text.TextWatcher import android.view.View import android.view.WindowManager import android.view.inputmethod.InputMethodManager diff --git a/app/src/main/java/io/heckel/ntfy/ui/DetailAdapter.kt b/app/src/main/java/io/heckel/ntfy/ui/DetailAdapter.kt index 9aca884..c3a08fe 100644 --- a/app/src/main/java/io/heckel/ntfy/ui/DetailAdapter.kt +++ b/app/src/main/java/io/heckel/ntfy/ui/DetailAdapter.kt @@ -25,16 +25,18 @@ import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import com.google.android.material.button.MaterialButton import com.stfalcon.imageviewer.StfalconImageViewer -import io.heckel.ntfy.BuildConfig import io.heckel.ntfy.R import io.heckel.ntfy.db.* -import io.heckel.ntfy.msg.DownloadManager import io.heckel.ntfy.msg.DownloadAttachmentWorker +import io.heckel.ntfy.msg.DownloadManager import io.heckel.ntfy.msg.DownloadType import io.heckel.ntfy.msg.NotificationService import io.heckel.ntfy.msg.NotificationService.Companion.ACTION_VIEW import io.heckel.ntfy.util.* -import kotlinx.coroutines.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch class DetailAdapter(private val activity: Activity, private val lifecycleScope: CoroutineScope, private val repository: Repository, private val onClick: (Notification) -> Unit, private val onLongClick: (Notification) -> Unit) : ListAdapter(TopicDiffCallback) { @@ -204,7 +206,7 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope: } private fun maybeRenderActions(context: Context, notification: Notification) { - if (notification.actions != null && notification.actions.isNotEmpty()) { + if (!notification.actions.isNullOrEmpty()) { actionsWrapperView.visibility = View.VISIBLE val actionsCount = Math.min(notification.actions.size, 3) // per documentation, only 3 actions are available for (i in 0 until actionsCount) { @@ -220,7 +222,7 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope: private fun resetCardButtons() { // clear any previously created dynamic buttons - actionsFlow.allViews.forEach { it -> actionsFlow.removeView(it) } + actionsFlow.allViews.forEach { actionsFlow.removeView(it) } actionsWrapperView.removeAllViews() actionsWrapperView.addView(actionsFlow) } diff --git a/app/src/main/java/io/heckel/ntfy/ui/DetailSettingsActivity.kt b/app/src/main/java/io/heckel/ntfy/ui/DetailSettingsActivity.kt index 91b41d1..82a4072 100644 --- a/app/src/main/java/io/heckel/ntfy/ui/DetailSettingsActivity.kt +++ b/app/src/main/java/io/heckel/ntfy/ui/DetailSettingsActivity.kt @@ -175,9 +175,8 @@ class DetailSettingsActivity : AppCompatActivity() { return subscription.mutedUntil.toString() } } - pref?.summaryProvider = Preference.SummaryProvider { _ -> - val mutedUntilValue = subscription.mutedUntil - when (mutedUntilValue) { + pref?.summaryProvider = Preference.SummaryProvider { + when (val mutedUntilValue = subscription.mutedUntil) { Repository.MUTED_UNTIL_SHOW_ALL -> getString(R.string.settings_notifications_muted_until_show_all) Repository.MUTED_UNTIL_FOREVER -> getString(R.string.settings_notifications_muted_until_forever) else -> { @@ -258,7 +257,7 @@ class DetailSettingsActivity : AppCompatActivity() { iconSetPref = findPreference(prefId) ?: return iconSetPref.isVisible = subscription.icon == null iconSetPref.preferenceDataStore = object : PreferenceDataStore() { } // Dummy store to protect from accidentally overwriting - iconSetPref.onPreferenceClickListener = Preference.OnPreferenceClickListener { _ -> + iconSetPref.onPreferenceClickListener = Preference.OnPreferenceClickListener { iconSetLauncher.launch("image/*") true } @@ -269,7 +268,7 @@ class DetailSettingsActivity : AppCompatActivity() { iconRemovePref = findPreference(prefId) ?: return iconRemovePref.isVisible = subscription.icon != null iconRemovePref.preferenceDataStore = object : PreferenceDataStore() { } // Dummy store to protect from accidentally overwriting - iconRemovePref.onPreferenceClickListener = Preference.OnPreferenceClickListener { _ -> + iconRemovePref.onPreferenceClickListener = Preference.OnPreferenceClickListener { iconRemovePref.isVisible = false iconSetPref.isVisible = true deleteIcon(subscription.icon) diff --git a/app/src/main/java/io/heckel/ntfy/ui/MainAdapter.kt b/app/src/main/java/io/heckel/ntfy/ui/MainAdapter.kt index 4d95d0e..f2a9ea6 100644 --- a/app/src/main/java/io/heckel/ntfy/ui/MainAdapter.kt +++ b/app/src/main/java/io/heckel/ntfy/ui/MainAdapter.kt @@ -1,9 +1,7 @@ package io.heckel.ntfy.ui import android.content.Context -import android.graphics.BitmapFactory import android.graphics.Color -import android.net.Uri import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -17,10 +15,8 @@ import io.heckel.ntfy.R import io.heckel.ntfy.db.ConnectionState import io.heckel.ntfy.db.Repository import io.heckel.ntfy.db.Subscription -import io.heckel.ntfy.msg.NotificationService -import io.heckel.ntfy.util.Log -import io.heckel.ntfy.util.readBitmapFromUriOrNull import io.heckel.ntfy.util.displayName +import io.heckel.ntfy.util.readBitmapFromUriOrNull import java.text.DateFormat import java.util.* diff --git a/app/src/main/java/io/heckel/ntfy/ui/MainViewModel.kt b/app/src/main/java/io/heckel/ntfy/ui/MainViewModel.kt index 84857db..19e384c 100644 --- a/app/src/main/java/io/heckel/ntfy/ui/MainViewModel.kt +++ b/app/src/main/java/io/heckel/ntfy/ui/MainViewModel.kt @@ -8,10 +8,8 @@ import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope import io.heckel.ntfy.db.* import io.heckel.ntfy.up.Distributor -import io.heckel.ntfy.util.Log import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import kotlin.collections.List class SubscriptionsViewModel(private val repository: Repository) : ViewModel() { fun list(): LiveData> { diff --git a/app/src/main/java/io/heckel/ntfy/ui/NotificationFragment.kt b/app/src/main/java/io/heckel/ntfy/ui/NotificationFragment.kt index 8509e8e..2d84879 100644 --- a/app/src/main/java/io/heckel/ntfy/ui/NotificationFragment.kt +++ b/app/src/main/java/io/heckel/ntfy/ui/NotificationFragment.kt @@ -8,7 +8,6 @@ import android.widget.RadioButton import androidx.fragment.app.DialogFragment import androidx.lifecycle.lifecycleScope import io.heckel.ntfy.R -import io.heckel.ntfy.db.Database import io.heckel.ntfy.db.Repository import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay diff --git a/app/src/main/java/io/heckel/ntfy/ui/UserFragment.kt b/app/src/main/java/io/heckel/ntfy/ui/UserFragment.kt index d4a7097..6da8304 100644 --- a/app/src/main/java/io/heckel/ntfy/ui/UserFragment.kt +++ b/app/src/main/java/io/heckel/ntfy/ui/UserFragment.kt @@ -3,13 +3,11 @@ package io.heckel.ntfy.ui import android.app.AlertDialog import android.app.Dialog import android.content.Context -import android.os.Build import android.os.Bundle import android.view.View import android.view.WindowManager import android.widget.Button import android.widget.TextView -import androidx.core.content.ContextCompat import androidx.fragment.app.DialogFragment import com.google.android.material.textfield.TextInputEditText import io.heckel.ntfy.R diff --git a/app/src/main/java/io/heckel/ntfy/up/BroadcastReceiver.kt b/app/src/main/java/io/heckel/ntfy/up/BroadcastReceiver.kt index 9119e15..23f1985 100644 --- a/app/src/main/java/io/heckel/ntfy/up/BroadcastReceiver.kt +++ b/app/src/main/java/io/heckel/ntfy/up/BroadcastReceiver.kt @@ -10,12 +10,10 @@ import io.heckel.ntfy.service.SubscriberServiceManager import io.heckel.ntfy.util.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import java.util.* -import kotlin.random.Random /** * This is the UnifiedPush broadcast receiver to handle the distributor actions REGISTER and UNREGISTER. diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 2d4f08c..31f29e3 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -309,7 +309,7 @@ Darstellung Abo-Icon Ein Icon zur Darstellung in Benachrichtigungen auswählen - Abo-Icon (entfernen durch antippen) + Abo-Icon (entfernen durch Antippen) Kann Icon nicht speichern: %1$s Globale Einstellung verwenden globale Einstellung @@ -323,9 +323,9 @@ Service-URL löschen %1$s (Standard) Anzeigename - Gib einen eigenen Anzeigenamen für diese Abo an. Leer lassen für den Standardwert (%1$s). + Gib einen eigenen Anzeigenamen für dieses Abo an. Leer lassen für den Standardwert (%1$s). Themen-URL Über In Zwischenablage kopiert Spenden 💸 - \ No newline at end of file + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d26c9d9..f7ac0c1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -318,7 +318,7 @@ Apps cannot receive notifications as broadcasts Record logs Logging (up to 1,000 entries) to device … - Turn on logging so you can share logs later to diagnose issues. + Turn on logging, so you can share logs later to diagnose issues. Copy/upload logs Copy logs to the clipboard, or upload to nopaste.net (owned by the ntfy author). Hostnames and topics can be censored, notifications will never be. Copy to clipboard From f43305646b0d7a0f15bee5f3d86b10cad246d027 Mon Sep 17 00:00:00 2001 From: Christian Meis Date: Tue, 6 Dec 2022 09:43:50 +0000 Subject: [PATCH 19/26] Translated using Weblate (German) Currently translated at 100.0% (319 of 319 strings) Translation: ntfy/Android app Translate-URL: https://hosted.weblate.org/projects/ntfy/android/de/ --- app/src/main/res/values-de/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 2d4f08c..ec6d3da 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -328,4 +328,5 @@ Über In Zwischenablage kopiert Spenden 💸 + Apps können nicht mehr installiert werden. Bitte stattdessen über einen Browser herunterladen. Details siehe Issue #531. \ No newline at end of file From a98200a0fb084957df4edf23189a9719097e8f90 Mon Sep 17 00:00:00 2001 From: 109247019824 Date: Tue, 6 Dec 2022 05:33:38 +0000 Subject: [PATCH 20/26] Translated using Weblate (Bulgarian) Currently translated at 100.0% (319 of 319 strings) Translation: ntfy/Android app Translate-URL: https://hosted.weblate.org/projects/ntfy/android/bg/ --- app/src/main/res/values-bg/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index fc6777e..7b8bb8c 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -328,4 +328,5 @@ Адрес на темата Копирано в междинната памет Даряване 💸 + Ntfy не може да инсталира получени приложения. Вместо това изтеглете чрез браузъра. За подробности вижте дефект №531. \ No newline at end of file From ef79192a16914833649301d56d793038dd3ac630 Mon Sep 17 00:00:00 2001 From: Rogelio Dominguez Date: Tue, 6 Dec 2022 22:47:03 +0000 Subject: [PATCH 21/26] Translated using Weblate (Spanish) Currently translated at 100.0% (319 of 319 strings) Translation: ntfy/Android app Translate-URL: https://hosted.weblate.org/projects/ntfy/android/es/ --- app/src/main/res/values-es/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 56ad002..4615748 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -328,4 +328,5 @@ Cambiar a WebSockets es la forma recomendada para conectarse a su servidor, y podría mejorar la vida de la batería, pero puede requerir configuración adicional en su proxy. Esto se puede cambiar en la Configuración. Habilitar ahora Donar 💸 + Las aplicaciones ya no se pueden instalar desde ntfy. Descárguelas a través del navegador. Consulte el issue #531 para obtener más información. \ No newline at end of file From 1c13ea9a38a9281f96030c343b3c0ea3476680bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuz=20Ersen?= Date: Tue, 6 Dec 2022 04:02:30 +0000 Subject: [PATCH 22/26] Translated using Weblate (Turkish) Currently translated at 100.0% (319 of 319 strings) Translation: ntfy/Android app Translate-URL: https://hosted.weblate.org/projects/ntfy/android/tr/ --- app/src/main/res/values-tr/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 393ec47..ce45f6f 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -328,4 +328,5 @@ Konu URL\'si Panoya kopyalandı Bağış yap 💸 + Uygulamalar artık kurulamıyor. Bunun yerine tarayıcı üzerinden indirin. Ayrıntılar için sorun #531\'e bakın. \ No newline at end of file From 9cc021d857b05a20ab770b592f724ebbb8103816 Mon Sep 17 00:00:00 2001 From: Eric Date: Tue, 6 Dec 2022 02:07:03 +0000 Subject: [PATCH 23/26] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (319 of 319 strings) Translation: ntfy/Android app Translate-URL: https://hosted.weblate.org/projects/ntfy/android/zh_Hans/ --- app/src/main/res/values-zh-rCN/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index c0012bc..fe61fe6 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -328,4 +328,5 @@ 话题 URL 已复制到剪贴板 捐赠 💸 + 无法再安装应用。 请通过浏览器下载。 有关详细信息,请参阅问题 #531。 \ No newline at end of file From c625d69ee3e4861a99e7352e574858dbef26ad66 Mon Sep 17 00:00:00 2001 From: Linerly Date: Tue, 6 Dec 2022 05:10:24 +0000 Subject: [PATCH 24/26] Translated using Weblate (Indonesian) Currently translated at 100.0% (319 of 319 strings) Translation: ntfy/Android app Translate-URL: https://hosted.weblate.org/projects/ntfy/android/id/ --- app/src/main/res/values-in/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index fda4855..9718910 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -328,4 +328,5 @@ Tentang URL Topik Donasi 💸 + Aplikasi tidak dapat dipasang lagi. Unduh melalui peramban. Lihat masalah #531 untuk detail lebih lanjut. \ No newline at end of file From 0089e217bd9181f85e2c39a1d208c6edbe4a7d63 Mon Sep 17 00:00:00 2001 From: Shoshin Akamine Date: Tue, 6 Dec 2022 09:47:36 +0000 Subject: [PATCH 25/26] Translated using Weblate (Japanese) Currently translated at 100.0% (319 of 319 strings) Translation: ntfy/Android app Translate-URL: https://hosted.weblate.org/projects/ntfy/android/ja/ --- app/src/main/res/values-ja/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 6d05912..e06e252 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -328,4 +328,5 @@ トピックのURL クリップボードにコピーしました 寄付する💸 + アプリはインストールできなくなりました。代替手段としてブラウザからダウンロードしてください。詳細は issue #531 をご参照ください。 \ No newline at end of file From 0226feb98311778c0ba3bacbac24bdde2e2a249a Mon Sep 17 00:00:00 2001 From: waclaw66 Date: Tue, 6 Dec 2022 07:11:52 +0000 Subject: [PATCH 26/26] Translated using Weblate (Czech) Currently translated at 100.0% (319 of 319 strings) Translation: ntfy/Android app Translate-URL: https://hosted.weblate.org/projects/ntfy/android/cs/ --- app/src/main/res/values-cs/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index d44c7f0..35c596d 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -328,4 +328,5 @@ WebSockets jsou doporučenou metodou připojení k vašemu serveru, která může zlepšit zvýšit výdrž baterie, ale může vyžadovat další konfiguraci v proxy serveru. Metodu připojení lze přepnout v Nastavení. Zvolit URL služby Přispět 💸 + Aplikace již nelze nainstalovat. Místo toho stahujte přes prohlížeč. Podrobnosti naleznete v issue #531. \ No newline at end of file