Merge branch 'main' into 236-android-action-buttons

This commit is contained in:
Philipp Heckel 2022-06-24 12:49:19 -04:00
commit b48cbcd19d
26 changed files with 231 additions and 48 deletions

View file

@ -2,11 +2,11 @@
"formatVersion": 1,
"database": {
"version": 12,
"identityHash": "b439720b55cf5e6bfdec2b56dd46103d",
"identityHash": "9363ad5196e88862acceb1bb9ee91124",
"entities": [
{
"tableName": "Subscription",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `baseUrl` TEXT NOT NULL, `topic` TEXT NOT NULL, `instant` INTEGER NOT NULL, `mutedUntil` INTEGER NOT NULL, `minPriority` INTEGER NOT NULL, `autoDelete` INTEGER NOT NULL, `lastNotificationId` TEXT, `icon` TEXT, `upAppId` TEXT, `upConnectorToken` TEXT, PRIMARY KEY(`id`))",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `baseUrl` TEXT NOT NULL, `topic` TEXT NOT NULL, `instant` INTEGER NOT NULL, `mutedUntil` INTEGER NOT NULL, `minPriority` INTEGER NOT NULL, `autoDelete` INTEGER NOT NULL, `lastNotificationId` TEXT, `icon` TEXT, `upAppId` TEXT, `upConnectorToken` TEXT, `displayName` TEXT, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
@ -73,6 +73,12 @@
"columnName": "upConnectorToken",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "displayName",
"columnName": "displayName",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
@ -320,7 +326,7 @@
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'b439720b55cf5e6bfdec2b56dd46103d')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '9363ad5196e88862acceb1bb9ee91124')"
]
}
}

View file

@ -100,7 +100,8 @@ class Backuper(val context: Context) {
lastNotificationId = s.lastNotificationId,
icon = s.icon,
upAppId = s.upAppId,
upConnectorToken = s.upConnectorToken
upConnectorToken = s.upConnectorToken,
displayName = s.displayName,
))
} catch (e: Exception) {
Log.w(TAG, "Unable to restore subscription ${s.id} (${topicUrl(s.baseUrl, s.topic)}): ${e.message}. Ignoring.", e)
@ -224,7 +225,8 @@ class Backuper(val context: Context) {
lastNotificationId = s.lastNotificationId,
icon = s.icon,
upAppId = s.upAppId,
upConnectorToken = s.upConnectorToken
upConnectorToken = s.upConnectorToken,
displayName = s.displayName
)
}
}
@ -331,7 +333,8 @@ data class Subscription(
val lastNotificationId: String?,
val icon: String?,
val upAppId: String?,
val upConnectorToken: String?
val upConnectorToken: String?,
val displayName: String?
)
data class Notification(

View file

@ -22,13 +22,14 @@ data class Subscription(
@ColumnInfo(name = "icon") val icon: String?, // content://-URI (or later other identifier)
@ColumnInfo(name = "upAppId") val upAppId: String?, // UnifiedPush application package name
@ColumnInfo(name = "upConnectorToken") val upConnectorToken: String?, // UnifiedPush connector token
@ColumnInfo(name = "displayName") val displayName: String?,
@Ignore val totalCount: Int = 0, // Total notifications
@Ignore val newCount: Int = 0, // New notifications
@Ignore val lastActive: Long = 0, // Unix timestamp
@Ignore val state: ConnectionState = ConnectionState.NOT_APPLICABLE
) {
constructor(id: Long, baseUrl: String, topic: String, instant: Boolean, mutedUntil: Long, minPriority: Int, autoDelete: Long, lastNotificationId: String, icon: String, upAppId: String, upConnectorToken: String) :
this(id, baseUrl, topic, instant, mutedUntil, minPriority, autoDelete, lastNotificationId, icon, upAppId, upConnectorToken, 0, 0, 0, ConnectionState.NOT_APPLICABLE)
constructor(id: Long, baseUrl: String, topic: String, instant: Boolean, mutedUntil: Long, minPriority: Int, autoDelete: Long, lastNotificationId: String, icon: String, upAppId: String, upConnectorToken: String, displayName: String?) :
this(id, baseUrl, topic, instant, mutedUntil, minPriority, autoDelete, lastNotificationId, icon, upAppId, upConnectorToken, displayName, 0, 0, 0, ConnectionState.NOT_APPLICABLE)
}
enum class ConnectionState {
@ -47,6 +48,7 @@ data class SubscriptionWithMetadata(
val icon: String?,
val upAppId: String?,
val upConnectorToken: String?,
val displayName: String?,
val totalCount: Int,
val newCount: Int,
val lastActive: Long
@ -266,6 +268,7 @@ abstract class Database : RoomDatabase() {
private val MIGRATION_11_12 = object : Migration(11, 12) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Subscription ADD COLUMN lastNotificationId TEXT")
db.execSQL("ALTER TABLE Subscription ADD COLUMN displayName TEXT")
}
}
}
@ -275,7 +278,7 @@ abstract class Database : RoomDatabase() {
interface SubscriptionDao {
@Query("""
SELECT
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken,
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken, s.displayName,
COUNT(n.id) totalCount,
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
IFNULL(MAX(n.timestamp),0) AS lastActive
@ -288,7 +291,7 @@ interface SubscriptionDao {
@Query("""
SELECT
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken,
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken, s.displayName,
COUNT(n.id) totalCount,
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
IFNULL(MAX(n.timestamp),0) AS lastActive
@ -301,7 +304,7 @@ interface SubscriptionDao {
@Query("""
SELECT
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken,
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken, s.displayName,
COUNT(n.id) totalCount,
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
IFNULL(MAX(n.timestamp),0) AS lastActive
@ -314,7 +317,7 @@ interface SubscriptionDao {
@Query("""
SELECT
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken,
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken, s.displayName,
COUNT(n.id) totalCount,
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
IFNULL(MAX(n.timestamp),0) AS lastActive
@ -327,7 +330,7 @@ interface SubscriptionDao {
@Query("""
SELECT
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken,
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken, s.displayName,
COUNT(n.id) totalCount,
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
IFNULL(MAX(n.timestamp),0) AS lastActive

View file

@ -384,6 +384,7 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
icon = s.icon,
upAppId = s.upAppId,
upConnectorToken = s.upConnectorToken,
displayName = s.displayName,
totalCount = s.totalCount,
newCount = s.newCount,
lastActive = s.lastActive,
@ -408,6 +409,7 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
icon = s.icon,
upAppId = s.upAppId,
upConnectorToken = s.upConnectorToken,
displayName = s.displayName,
totalCount = s.totalCount,
newCount = s.newCount,
lastActive = s.lastActive,

View file

@ -300,6 +300,7 @@ class NotificationService(val context: Context) {
putExtra(MainActivity.EXTRA_SUBSCRIPTION_ID, subscription.id)
putExtra(MainActivity.EXTRA_SUBSCRIPTION_BASE_URL, subscription.baseUrl)
putExtra(MainActivity.EXTRA_SUBSCRIPTION_TOPIC, subscription.topic)
putExtra(MainActivity.EXTRA_SUBSCRIPTION_DISPLAY_NAME, displayName(subscription))
putExtra(MainActivity.EXTRA_SUBSCRIPTION_INSTANT, subscription.instant)
putExtra(MainActivity.EXTRA_SUBSCRIPTION_MUTED_UNTIL, subscription.mutedUntil)
}

View file

@ -54,6 +54,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
private var subscriptionId: Long = 0L // Set in onCreate()
private var subscriptionBaseUrl: String = "" // Set in onCreate()
private var subscriptionTopic: String = "" // Set in onCreate()
private var subscriptionDisplayName: String = "" // Set in onCreate() & updated by options menu!
private var subscriptionInstant: Boolean = false // Set in onCreate() & updated by options menu!
private var subscriptionMutedUntil: Long = 0L // Set in onCreate() & updated by options menu!
@ -116,6 +117,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
icon = null,
upAppId = null,
upConnectorToken = null,
displayName = null,
totalCount = 0,
newCount = 0,
lastActive = Date().time/1000
@ -147,6 +149,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_ID, subscription.id)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_BASE_URL, subscription.baseUrl)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_TOPIC, subscription.topic)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_DISPLAY_NAME, displayName(subscription))
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_INSTANT, subscription.instant)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_MUTED_UNTIL, subscription.mutedUntil)
@ -161,13 +164,14 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
subscriptionId = intent.getLongExtra(MainActivity.EXTRA_SUBSCRIPTION_ID, 0)
subscriptionBaseUrl = intent.getStringExtra(MainActivity.EXTRA_SUBSCRIPTION_BASE_URL) ?: return
subscriptionTopic = intent.getStringExtra(MainActivity.EXTRA_SUBSCRIPTION_TOPIC) ?: return
subscriptionDisplayName = intent.getStringExtra(MainActivity.EXTRA_SUBSCRIPTION_DISPLAY_NAME) ?: return
subscriptionInstant = intent.getBooleanExtra(MainActivity.EXTRA_SUBSCRIPTION_INSTANT, false)
subscriptionMutedUntil = intent.getLongExtra(MainActivity.EXTRA_SUBSCRIPTION_MUTED_UNTIL, 0L)
// Set title
val subscriptionBaseUrl = intent.getStringExtra(MainActivity.EXTRA_SUBSCRIPTION_BASE_URL) ?: return
val topicUrl = topicShortUrl(subscriptionBaseUrl, subscriptionTopic)
title = topicUrl
title = subscriptionDisplayName
// Set "how to instructions"
val howToExample: TextView = findViewById(R.id.detail_how_to_example)
@ -263,9 +267,11 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
val subscription = repository.getSubscription(subscriptionId) ?: return@launch
subscriptionInstant = subscription.instant
subscriptionMutedUntil = subscription.mutedUntil
subscriptionDisplayName = displayName(subscription)
showHideInstantMenuItems(subscriptionInstant)
showHideMutedUntilMenuItems(subscriptionMutedUntil)
updateTitle(subscriptionDisplayName)
}
}
@ -543,6 +549,12 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
}
}
private fun updateTitle(subscriptionDisplayName: String) {
runOnUiThread {
title = subscriptionDisplayName
}
}
private fun onClearClick() {
Log.d(TAG, "Clearing all notifications for ${topicShortUrl(subscriptionBaseUrl, subscriptionTopic)}")
@ -571,6 +583,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
intent.putExtra(EXTRA_SUBSCRIPTION_ID, subscriptionId)
intent.putExtra(EXTRA_SUBSCRIPTION_BASE_URL, subscriptionBaseUrl)
intent.putExtra(EXTRA_SUBSCRIPTION_TOPIC, subscriptionTopic)
intent.putExtra(EXTRA_SUBSCRIPTION_DISPLAY_NAME, subscriptionDisplayName)
startActivity(intent)
}
@ -747,5 +760,6 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
const val EXTRA_SUBSCRIPTION_ID = "subscriptionId"
const val EXTRA_SUBSCRIPTION_BASE_URL = "baseUrl"
const val EXTRA_SUBSCRIPTION_TOPIC = "topic"
const val EXTRA_SUBSCRIPTION_DISPLAY_NAME = "displayName"
}
}

View file

@ -4,6 +4,7 @@ import android.content.ContentResolver
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Bundle
import android.text.TextUtils
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
@ -55,9 +56,8 @@ class DetailSettingsActivity : AppCompatActivity() {
}
// Title
val baseUrl = intent.getStringExtra(DetailActivity.EXTRA_SUBSCRIPTION_BASE_URL) ?: return
val topic = intent.getStringExtra(DetailActivity.EXTRA_SUBSCRIPTION_TOPIC) ?: return
title = topicShortUrl(baseUrl, topic)
val displayName = intent.getStringExtra(DetailActivity.EXTRA_SUBSCRIPTION_DISPLAY_NAME) ?: return
title = displayName
// Show 'Back' button
supportActionBar?.setDisplayHomeAsUpEnabled(true)
@ -108,6 +108,7 @@ class DetailSettingsActivity : AppCompatActivity() {
loadAutoDeletePref()
loadIconSetPref()
loadIconRemovePref()
loadDisplayNamePref()
}
private fun loadInstantPref() {
@ -276,6 +277,40 @@ class DetailSettingsActivity : AppCompatActivity() {
}
}
private fun loadDisplayNamePref() {
val prefId = context?.getString(R.string.detail_settings_appearance_display_name_key) ?: return
val pref: EditTextPreference? = findPreference(prefId)
pref?.isVisible = true // Hack: Show all settings at once, because subscription is loaded asynchronously
pref?.text = subscription.displayName
pref?.preferenceDataStore = object : PreferenceDataStore() {
override fun putString(key: String?, value: String?) {
val displayName: String? = if (value == "") {
null
} else {
value
}
val newSubscription = subscription.copy(displayName = displayName)
save(newSubscription)
activity?.runOnUiThread {
activity?.title = displayName(newSubscription)
}
}
override fun getString(key: String?, defValue: String?): String {
return subscription.displayName ?: ""
}
}
pref?.summaryProvider = Preference.SummaryProvider<EditTextPreference> { provider ->
if (TextUtils.isEmpty(provider.text)) {
getString(
R.string.detail_settings_appearance_display_name_default_summary,
displayName(subscription)
)
} else {
provider.text
}
}
}
private fun createIconPickLauncher(): ActivityResultLauncher<String> {
return registerForActivityResult(ActivityResultContracts.GetContent()) { inputUri ->
if (inputUri == null) {

View file

@ -438,6 +438,7 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
icon = null,
upAppId = null,
upConnectorToken = null,
displayName = null,
totalCount = 0,
newCount = 0,
lastActive = Date().time/1000
@ -509,7 +510,7 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
}
}
} catch (e: Exception) {
val topic = topicShortUrl(subscription.baseUrl, subscription.topic)
val topic = displayName(subscription)
if (errorMessage == "") errorMessage = "$topic: ${e.message}"
errors++
}
@ -536,6 +537,7 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
intent.putExtra(EXTRA_SUBSCRIPTION_ID, subscription.id)
intent.putExtra(EXTRA_SUBSCRIPTION_BASE_URL, subscription.baseUrl)
intent.putExtra(EXTRA_SUBSCRIPTION_TOPIC, subscription.topic)
intent.putExtra(EXTRA_SUBSCRIPTION_DISPLAY_NAME, displayName(subscription))
intent.putExtra(EXTRA_SUBSCRIPTION_INSTANT, subscription.instant)
intent.putExtra(EXTRA_SUBSCRIPTION_MUTED_UNTIL, subscription.mutedUntil)
startActivity(intent)
@ -662,6 +664,7 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
const val EXTRA_SUBSCRIPTION_ID = "subscriptionId"
const val EXTRA_SUBSCRIPTION_BASE_URL = "subscriptionBaseUrl"
const val EXTRA_SUBSCRIPTION_TOPIC = "subscriptionTopic"
const val EXTRA_SUBSCRIPTION_DISPLAY_NAME = "subscriptionDisplayName"
const val EXTRA_SUBSCRIPTION_INSTANT = "subscriptionInstant"
const val EXTRA_SUBSCRIPTION_MUTED_UNTIL = "subscriptionMutedUntil"
const val ANIMATION_DURATION = 80L

View file

@ -20,7 +20,7 @@ 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.topicShortUrl
import io.heckel.ntfy.util.displayName
import java.text.DateFormat
import java.util.*
@ -101,7 +101,7 @@ class MainAdapter(private val repository: Repository, private val onClick: (Subs
if (subscription.icon != null) {
imageView.setImageBitmap(subscription.icon.readBitmapFromUriOrNull(context))
}
nameView.text = topicShortUrl(subscription.baseUrl, subscription.topic)
nameView.text = displayName(subscription)
statusView.text = statusMessage
dateView.text = dateText
dateView.visibility = if (isUnifiedPush) View.GONE else View.VISIBLE

View file

@ -79,6 +79,7 @@ class BroadcastReceiver : android.content.BroadcastReceiver() {
icon = null,
upAppId = appId,
upConnectorToken = connectorToken,
displayName = null,
totalCount = 0,
newCount = 0,
lastActive = Date().time/1000

View file

@ -53,6 +53,10 @@ fun topicUrlAuth(baseUrl: String, topic: String) = "${topicUrl(baseUrl, topic)}/
fun topicUrlJsonPoll(baseUrl: String, topic: String, since: String) = "${topicUrl(baseUrl, topic)}/json?poll=1&since=$since"
fun topicShortUrl(baseUrl: String, topic: String) = shortUrl(topicUrl(baseUrl, topic))
fun displayName(subscription: Subscription) : String {
return subscription.displayName ?: topicShortUrl(subscription.baseUrl, subscription.topic)
}
fun shortUrl(url: String) = url
.replace("http://", "")
.replace("https://", "")
@ -176,7 +180,7 @@ fun formatTitle(subscription: Subscription, notification: Notification): String
return if (notification.title != "") {
formatTitle(notification)
} else {
topicShortUrl(subscription.baseUrl, subscription.topic)
displayName(subscription)
}
}

View file

@ -174,7 +174,7 @@
<string name="settings_general_users_prefs_user_add_title">Добавяне на потребител</string>
<string name="settings_advanced_header">Разширени</string>
<string name="user_dialog_button_cancel">Отказ</string>
<string name="settings_advanced_connection_protocol_summary_ws">Използвайте WebSockets за свързване със сървъра. Това е експериментална възможност. Дайте ни обратна връзка дали се изразходва по-малко батерия или е нестабилна.</string>
<string name="settings_advanced_connection_protocol_summary_ws">Използва се WebSockets за свързване със сървъра. Това е препоръчителния метод, но могат да се наложат настройки на сървъра за прокси.</string>
<string name="settings_advanced_export_logs_title">Копиране или изпращане на дневник</string>
<string name="settings_advanced_export_logs_entry_copy_original">Копиране в междинната памет</string>
<string name="settings_advanced_export_logs_scrub_dialog_button_ok">Добре</string>
@ -183,7 +183,7 @@
<string name="settings_notifications_auto_delete_three_months">След три месеца</string>
<string name="settings_notifications_auto_delete_one_month">След един месец</string>
<string name="settings_advanced_export_logs_entry_copy_scrubbed">Копиране в междинната памет (цензурирано)</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">За свързване със сървъра се използва поток от JSON през HTTP. Методът е остарял и ще бъде премахнат през месец юни 2022 год.</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">За свързване със сървъра се използва поток от JSON през HTTP. Методът е изпитан, но може да използва повече батерия.</string>
<string name="detail_test_message">Това е пробно известие от приложението ntfy за Android. То е с приоритет %1$d. Ако изпратите друго, то може да изглежда по различен начин.</string>
<string name="detail_test_title">Проба: Ако желаете можете да сложите заглавие</string>
<string name="detail_test_message_error_unauthorized_user">Грешка при изпращане: Потребителят „%1$s“ няма достъп.</string>
@ -319,4 +319,6 @@
<string name="detail_settings_global_setting_suffix">от общите настройки</string>
<string name="add_dialog_base_urls_dropdown_choose">Изберете адрес на услугата</string>
<string name="add_dialog_base_urls_dropdown_clear">Изчистване на адреса на услугата</string>
</resources>
<string name="main_banner_websocket_text">WebSockets е препоръчителния начин за свързване с услугата и може да подобри използването на батерията, но могат да се наложат <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">допълнителни настройки на сървъра за прокси</a>. Промяната може да бъде направена в настройките.</string>
<string name="main_banner_websocket_button_enable_now">Включване</string>
</resources>

View file

@ -211,9 +211,9 @@
<string name="settings_advanced_clear_logs_summary">Vorhandene Logs löschen und neu beginnen</string>
<string name="settings_advanced_clear_logs_deleted_toast">Logs gelöscht</string>
<string name="settings_advanced_connection_protocol_title">Verbindungs-Protokoll</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">JSON-over-HTTP-Stream für die Serververbindung nutzen. Diese Methode ist veraltet und wird im Juni 2022 entfernt.</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">JSON-over-HTTP-Stream für die Serververbindung nutzen. Diese Methode ist bewährt, benötigt aber evtl. mehr Akku.</string>
<string name="settings_advanced_broadcast_title">Nachrichten broadcasten</string>
<string name="settings_advanced_connection_protocol_summary_ws">WebSockets für die Server-Verbindung nutzen. Diese Methode wird im Juni 2022 der Standard.</string>
<string name="settings_advanced_connection_protocol_summary_ws">WebSockets für die Server-Verbindung nutzen. Diese Methode wird empfohlen, benötigt aber evtl. zusätzliche Konfiguration in Deinem Proxy.</string>
<string name="settings_advanced_connection_protocol_entry_jsonhttp">JSON-over-HTTP-Stream</string>
<string name="settings_advanced_connection_protocol_entry_ws">WebSockets</string>
<string name="settings_about_header">Über</string>
@ -317,4 +317,8 @@
<string name="detail_settings_notifications_instant_title">Sofortnachrichten</string>
<string name="detail_settings_appearance_icon_remove_summary">Icon, das in Benachrichtigungen zu diesem Thema angezeigt wird</string>
<string name="detail_settings_notifications_instant_summary_on">Benachrichtigungen werden sofort zugestellt. Benötigt einen Vordergrund-Dienst und verbraucht mehr Akku.</string>
</resources>
<string name="main_banner_websocket_text">Der Umstieg auf WebSockets ist die empfohlene Verbindungsweise zu Deinem Server und benötigt möglicherweise weniger Akkuleistung. Es könnte aber eine <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">zusätzliche Konfiguration im Proxy</a> nötig sein. Die Verbindungmethode kann in den Einstellungen gewählt werden.</string>
<string name="main_banner_websocket_button_enable_now">Jetzt aktivieren</string>
<string name="add_dialog_base_urls_dropdown_choose">Service-URL wählen</string>
<string name="add_dialog_base_urls_dropdown_clear">Service-URL löschen</string>
</resources>

View file

@ -286,8 +286,8 @@
<string name="settings_advanced_export_logs_copied_logs">Journaux copiés dans le presse-papier</string>
<string name="settings_advanced_export_logs_summary">Copier les journaux dans le presse-papier ou les télécharger sur nopaste.net (détenu par l\'auteur de ntfy). Les noms d\'hôtes et les sujets peuvent être censurés, les notifications ne le seront jamais.</string>
<string name="settings_advanced_export_logs_copied_url">Journaux téléchargés et URL copiée</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Utiliser un flux JSON en HTTP pour se connecter au serveur. Cette méthode est dépréciée et sera retirée en juin 2022.</string>
<string name="settings_advanced_connection_protocol_summary_ws">Utiliser des WebSockets pour se connecter au serveur. Cela deviendra la valeur par défaut en juin 2022.</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Utiliser un flux JSON en HTTP pour se connecter au serveur. Cette méthode est éprouvée, mais peut consommer plus de batterie.</string>
<string name="settings_advanced_connection_protocol_summary_ws">Utiliser des WebSockets pour se connecter au serveur. Il s\'agit de la méthode recommandée, mais peut requérir une configuration supplémentaire de votre proxy.</string>
<string name="settings_about_version_copied_to_clipboard_message">Copié dans le presse-papier</string>
<string name="settings_advanced_record_logs_title">Enregistrer les journaux</string>
<string name="user_dialog_description_add">Vous pouvez ajouter un utilisateur ici. Tous les sujets du serveur sélectionné utiliseront cet utilisateur.</string>
@ -317,4 +317,8 @@
<string name="detail_settings_appearance_icon_set_summary">Choisir une icône à afficher pour les notifications</string>
<string name="detail_settings_global_setting_title">Utiliser le paramètre global</string>
<string name="detail_settings_global_setting_suffix">utilisation du paramètre global</string>
</resources>
<string name="main_banner_websocket_text">Il est recommandé d\'utiliser les WebSockets pour vous connecter à votre serveur, ce qui peut également économiser la batterie, mais peut requérir <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">une configuration additionnelle de votre proxy</a>. Cela peut être changé dans les paramètres.</string>
<string name="add_dialog_base_urls_dropdown_choose">Choisir l\'URL du service</string>
<string name="add_dialog_base_urls_dropdown_clear">Supprimer l\'URL du service</string>
<string name="main_banner_websocket_button_enable_now">Activer maintenant</string>
</resources>

View file

@ -198,8 +198,8 @@
<string name="settings_advanced_clear_logs_summary">Hapus catatan yang direkam sebelumnya, dan mulai ulang</string>
<string name="settings_advanced_clear_logs_deleted_toast">Catatan dihapus</string>
<string name="settings_advanced_connection_protocol_title">Protokol koneksi</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Gunakan aliran JSON melalui HTTP untuk menghubungkan ke server. Mode ini usang dan akan dihilangkan di Juni 2022.</string>
<string name="settings_advanced_connection_protocol_summary_ws">Gunakan WebSockets untuk menghubungkan ke server. Ini adalah sebagai bawaan di Juni 2022.</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Gunakan aliran JSON melalui HTTP untuk menyambung ke server. Metode ini sudah teruji, tetapi mungkin menghabiskan lebih banyak baterai.</string>
<string name="settings_advanced_connection_protocol_summary_ws">Gunakan WebSockets untuk menyambung ke server. Ini adalah metode yang disarankan, tetapi mungkin memerlukan konfigurasi tambahan dalam proksi Anda.</string>
<string name="settings_advanced_connection_protocol_entry_jsonhttp">Aliran JSON melalui HTTP</string>
<string name="settings_advanced_connection_protocol_entry_ws">WebSockets</string>
<string name="settings_about_header">Tentang</string>
@ -306,8 +306,7 @@
<string name="channel_subscriber_notification_instant_text_six">Berlangganan ke enam topik pengiriman instan</string>
<string name="channel_subscriber_notification_noinstant_text_five">Berlangganan ke lima topik</string>
<string name="channel_subscriber_notification_noinstant_text_six">Berlangganan ke enam topik</string>
<string name="detail_settings_notifications_instant_summary_on">Notifikasi dikirim secara instan.
\nMembutuhkan sebuah layanan latar depan dan mengkonsumsi lebih banyak baterai.</string>
<string name="detail_settings_notifications_instant_summary_on">Notifikasi dikirim secara instan. Membutuhkan sebuah layanan latar depan dan mengkonsumsi lebih banyak baterai.</string>
<string name="detail_settings_appearance_header">Tampilan</string>
<string name="detail_settings_appearance_icon_set_summary">Tetapkan sebuah ikon untuk ditampilkan di notifikasi</string>
<string name="detail_settings_appearance_icon_remove_title">Ikon langganan (ketuk untuk menghapus)</string>
@ -320,4 +319,6 @@
<string name="detail_settings_appearance_icon_set_title">Ikon langganan</string>
<string name="add_dialog_base_urls_dropdown_choose">Pilih URL layanan</string>
<string name="add_dialog_base_urls_dropdown_clear">Hapus URL layanan</string>
</resources>
<string name="main_banner_websocket_text">Beralih ke WebSockets adalah cara yang disarankan untuk terhubung ke server Anda, dan dapat meningkatkan masa pakai baterai, tetapi mungkin memerlukan <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">konfigurasi tambahan di proksi Anda</a>. Ini dapat diubah di Pengaturan.</string>
<string name="main_banner_websocket_button_enable_now">Aktifkan sekarang</string>
</resources>

View file

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="channel_notifications_min_name">Notyfikacje (Minimalny Priorytet)</string>
<string name="channel_notifications_low_name">Notyfikacje (Niski priorytet)</string>
<string name="channel_notifications_default_name">Notyfikacje (domyślny priorytet)</string>
<string name="channel_notifications_max_name">Notyfikacje (Maksymalny priorytet)</string>
<string name="channel_subscriber_notification_title">Oczekiwanie powiadomień przychodzących</string>
<string name="channel_notifications_min_name">Powiadomienia (minimalny priorytet)</string>
<string name="channel_notifications_low_name">Powiadomienia (niski priorytet)</string>
<string name="channel_notifications_default_name">Powiadomienia (domyślny priorytet)</string>
<string name="channel_notifications_max_name">Powiadomienia (maksymalny priorytet)</string>
<string name="channel_subscriber_notification_title">Oczekiwanie na przychodzące powiadomienia</string>
<string name="channel_subscriber_notification_instant_text">Subskrybujesz tematy z natychmiastową dostawą</string>
<string name="channel_notifications_high_name">Notyfikacje (Wysoki Priorytet)</string>
<string name="channel_subscriber_service_name">Usługa Subskrypcji</string>
<string name="channel_notifications_high_name">Powiadomienia (wysoki priorytet)</string>
<string name="channel_subscriber_service_name">Usługa subskrypcji</string>
</resources>

View file

@ -172,8 +172,8 @@
<string name="settings_advanced_clear_logs_summary">Önceden kaydedilen günlükleri silin ve baştan başlayın</string>
<string name="settings_advanced_clear_logs_deleted_toast">Günlükler silindi</string>
<string name="settings_advanced_connection_protocol_title">Bağlantı protokolü</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Sunucuya bağlanmak için HTTP üzerinden bir JSON akışı kullanın. Bu yöntem kullanım dışıdır ve Haziran 2022\'de kaldırılacaktır.</string>
<string name="settings_advanced_connection_protocol_summary_ws">Sunucuya bağlanmak için WebSockets kullanın. Bu, Haziran 2022\'de öntanımlı olacaktır.</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Sunucuya bağlanmak için HTTP üzerinden bir JSON akışı kullanın. Bu yöntem iyi test edilmiştir, ancak daha fazla pil tüketebilir.</string>
<string name="settings_advanced_connection_protocol_summary_ws">Sunucuya bağlanmak için WebSockets kullanın. Bu tavsiye edilen yöntemdir, ancak vekilinizde ek yapılandırma gerektirebilir.</string>
<string name="channel_notifications_max_name">Bildirimler (en yüksek öncelik)</string>
<string name="channel_subscriber_notification_noinstant_text_two">İki konuya abone olundu</string>
<string name="main_add_button_description">Abonelik ekle</string>
@ -319,4 +319,6 @@
<string name="detail_settings_global_setting_title">Genel ayarı kullan</string>
<string name="add_dialog_base_urls_dropdown_clear">Hizmet URL\'sini temizle</string>
<string name="add_dialog_base_urls_dropdown_choose">Hizmet URL\'sini seç</string>
</resources>
<string name="main_banner_websocket_button_enable_now">Şimdi etkinleştir</string>
<string name="main_banner_websocket_text">WebSockets\'e geçmek sunucunuza bağlanmak için tavsiye edilen yoldur ve pil ömrünü artırabilir, ancak <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">vekilinizde ek yapılandırma</a> gerektirebilir. Bu, ayarlardan değiştirilebilir.</string>
</resources>

View file

@ -241,8 +241,8 @@
<string name="settings_advanced_export_logs_copied_url">日志已上传URL 已复制到剪贴板</string>
<string name="settings_advanced_export_logs_error_uploading">无法上传日志:%1$s</string>
<string name="settings_advanced_export_logs_scrub_dialog_button_ok">确认</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">使用通过 HTTP 传输的 JSON 数据流。该方式已废弃并将在 2022 年 6 月移除</string>
<string name="settings_advanced_connection_protocol_summary_ws">使用 WebSockets 连接到服务器。该方式将在 2022 年 6 月成为默认选项</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">使用通过 HTTP 传输的 JSON 数据流来连接至服务器。该方式经过实战检验但可能消耗更多电量</string>
<string name="settings_advanced_connection_protocol_summary_ws">使用 WebSockets 连接到服务器。这是推荐的方法,但可能需要在你的代理中进行额外配置</string>
<string name="settings_advanced_connection_protocol_entry_jsonhttp">HTTP 传输的 JSON 数据流</string>
<string name="settings_about_header">关于</string>
<string name="notification_popup_file_downloading">下载中 %1$s, %2$d%%
@ -317,4 +317,5 @@
<string name="detail_settings_appearance_icon_error_saving">无法保存图标:%1$s</string>
<string name="detail_settings_global_setting_title">使用全局设置</string>
<string name="detail_settings_global_setting_suffix">使用全局设置</string>
</resources>
<string name="add_dialog_base_urls_dropdown_choose">选择服务 URL</string>
</resources>

View file

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="channel_subscriber_notification_noinstant_text_six">已訂閱6個主題</string>
<string name="channel_notifications_default_name">通知(預設優先)</string>
<string name="main_menu_report_bug_title">回報bug</string>
<string name="channel_subscriber_notification_title">監聽傳入通知</string>
<string name="channel_subscriber_notification_instant_text">已訂閱即時推送主題</string>
<string name="channel_subscriber_notification_instant_text_one">已訂閱1個即時推送主題</string>
<string name="channel_subscriber_notification_instant_text_two">已訂閱2個即時推送主題</string>
<string name="channel_subscriber_notification_instant_text_four">已訂閱4個即時推送主題</string>
<string name="channel_subscriber_notification_instant_text_five">已訂閱5個即時推送主題</string>
<string name="channel_subscriber_notification_instant_text_six">已訂閱6個即時推送主題</string>
<string name="channel_subscriber_notification_instant_text_more">已訂閱%1$d個即時推送主題</string>
<string name="channel_subscriber_notification_noinstant_text">已訂閱主題</string>
<string name="refresh_message_result">收到%1$d個通知</string>
<string name="refresh_message_no_results">已同步到最新</string>
<string name="refresh_message_error">有%1$d個訂閱無法更新
\n
\n%2$s</string>
<string name="refresh_message_error_one">訂閱無法更新:%1$s</string>
<string name="main_action_bar_title">已訂閱主題</string>
<string name="main_menu_notifications_enabled">通知已開啟</string>
<string name="main_menu_notifications_disabled_forever">通知已靜音</string>
<string name="main_menu_settings_title">設定</string>
<string name="main_menu_rate_title">幫我們評個分⭐</string>
<string name="main_action_mode_menu_unsubscribe">取消訂閱</string>
<string name="main_action_mode_delete_dialog_message">取消訂閱已選取的主題且永久刪除所有通知?</string>
<string name="main_action_mode_delete_dialog_permanently_delete">永久刪除</string>
<string name="main_action_mode_delete_dialog_cancel">取消</string>
<string name="main_item_status_text_one">%1$d個通知</string>
<string name="main_item_status_text_not_one">%1$d個通知</string>
<string name="main_item_date_yesterday">昨天</string>
<string name="main_add_button_description">新增訂閱</string>
<string name="main_no_subscriptions_text">看來你還沒有訂閱任何主題。</string>
<string name="main_how_to_intro">點擊 + 來新增或訂閱一個主題。當透過 PUT 或 POST 來發送訊息你將會接收到通知。</string>
<string name="main_how_to_link">更多資訊請上 ntfy.shdocs會有更多說明。</string>
<string name="main_unified_push_toast">此訂閱已由 %1$s 透過 UnifiedPush 管理</string>
<string name="main_item_status_unified_push">%1$s (UnifiedPush)</string>
<string name="main_banner_battery_text">為了避免通知傳送問題,電池最佳化必須關閉。</string>
<string name="main_banner_battery_button_remind_later">稍後詢問我</string>
<string name="main_banner_battery_button_dismiss">略過</string>
<string name="main_banner_battery_button_fix_now">立即修正</string>
<string name="main_banner_websocket_button_remind_later">稍後詢問我</string>
<string name="main_banner_websocket_button_dismiss">略過</string>
<string name="main_banner_websocket_button_enable_now">立即啟用</string>
<string name="add_dialog_title">訂閱主題</string>
<string name="add_dialog_description_below">因為主題不能受密碼保護,請盡量取一個難以猜測的主題名稱。在訂閱之後你就可以使用 PUT/POST 來發送通知。</string>
<string name="add_dialog_use_another_server">使用其他伺服器</string>
<string name="add_dialog_use_another_server_description">在下方輸入自訂的網址來訂閱主題。</string>
<string name="channel_notifications_min_name">通知(最低優先)</string>
<string name="channel_notifications_low_name">通知(低優先)</string>
<string name="channel_notifications_high_name">通知(高優先)</string>
<string name="channel_notifications_max_name">通知(最高優先)</string>
<string name="channel_subscriber_service_name">訂閱服務</string>
<string name="channel_subscriber_notification_instant_text_three">已訂閱3個即時推送主題</string>
<string name="main_menu_docs_title">閱讀文件</string>
<string name="main_banner_websocket_text">建議使用 WebSockets 來連線你的伺服器,此動作可以有效增加電池續航,但需要<a href="https://ntfy.sh/docs/config/#nginxapache2caddy">對proxy進行更多設定</a>。這個動作可以在設定中進行。</string>
<string name="channel_subscriber_notification_noinstant_text_three">已訂閱3個主題</string>
<string name="channel_subscriber_notification_noinstant_text_more">已訂閱%1$d個主題</string>
<string name="channel_subscriber_notification_noinstant_text_one">已訂閱1個主題</string>
<string name="channel_subscriber_notification_noinstant_text_two">已訂閱2個主題</string>
<string name="channel_subscriber_notification_noinstant_text_four">已訂閱4個主題</string>
<string name="channel_subscriber_notification_noinstant_text_five">已訂閱5個主題</string>
<string name="main_item_status_reconnecting">重新連線中 …</string>
<string name="main_menu_notifications_disabled_until">通知靜音到%1$s</string>
<string name="add_dialog_topic_name_hint">主題名稱(例如:phils_alerts)</string>
</resources>

View file

@ -353,6 +353,9 @@
<string name="detail_settings_appearance_icon_remove_title">Subscription icon (tap to remove)</string>
<string name="detail_settings_appearance_icon_remove_summary">Icon displayed in notifications for this topic</string>
<string name="detail_settings_appearance_icon_error_saving">Unable to save icon: %1$s</string>
<string name="detail_settings_appearance_display_name_title">Display name</string>
<string name="detail_settings_appearance_display_name_message">Set a custom display name for this subscription. Leave empty for default.</string>
<string name="detail_settings_appearance_display_name_default_summary">%1$s (default)</string>
<string name="detail_settings_global_setting_title">Use global setting</string>
<string name="detail_settings_global_setting_suffix">using global setting</string>

View file

@ -36,6 +36,7 @@
<string name="detail_settings_notifications_auto_delete_key" translatable="false">SubscriptionAutoDelete</string>
<string name="detail_settings_appearance_icon_set_key" translatable="false">SubscriptionIconSet</string>
<string name="detail_settings_appearance_icon_remove_key" translatable="false">SubscriptionIconRemove</string>
<string name="detail_settings_appearance_display_name_key" translatable="false">SubscriptionDisplayName</string>
<!-- Main settings -->
<string-array name="settings_notifications_muted_until_entries">

View file

@ -38,5 +38,11 @@
app:title="@string/detail_settings_appearance_icon_remove_title"
app:summary="@string/detail_settings_appearance_icon_remove_summary"
app:isPreferenceVisible="false"/>
<EditTextPreference
app:key="@string/detail_settings_appearance_display_name_key"
app:title="@string/detail_settings_appearance_display_name_title"
app:dialogLayout="@layout/preference_dialog_edittext_edited"
app:dialogMessage="@string/detail_settings_appearance_display_name_message"
app:isPreferenceVisible="false"/>
</PreferenceCategory>
</PreferenceScreen>

View file

@ -1,4 +1,5 @@
Features:
* Subscriptions can now have a display name (#313, thanks to @wunter8)
* Polling is now done with since=<id> API, which makes deduping easier (#165)
* Turned JSON stream deprecation banner into "Use WebSockets" banner (no ticket)

View file

@ -0,0 +1,17 @@
Kirim notifikasi ke ponsel Anda dari skrip Bash atau PowerShell, atau dari aplikasi Anda sendiri menggunakan permintaan PUT/POST, misalnya melalui curl di Linux atau Invoke-WebRequest.
ntfy adalah klien Android untuk https://ntfy.sh, sebuah layanan pub-sub berbasis HTTP bebas dan sumber terbuka. Anda dapat berlangganan topik di aplikasi ini, dan kemudian mempublikasikan pesan melalui HTTP API sederhana.
Kegunaan:
* Memberitahu diri Anda sendiri saat proses yang berjalan lama selesai
* Ping ponsel Anda ketika pencadangan gagal
* Memberi peringatan ketika seseorang masuk ke server Anda
Contoh:
$ curl -d "Pencadangan Anda telah selesai" ntfy.sh/topiksaya
Temukan lebih banyak contoh dan instruksi penggunaan di sini:
* Situs web: https://ntfy.sh
* GitHub (server): https://github.com/binwiederhier/ntfy
* GitHub (aplikasi Android): https://github.com/binwiederhier/ntfy-android

View file

@ -0,0 +1 @@
Kirim notifikasi ke ponsel Anda dari skrip memakai permintaan PUT/POST

View file

@ -0,0 +1 @@
ntfy — PUT/POST ke ponsel Anda