Compare commits

..

1 commit
main ... dnd

Author SHA1 Message Date
Philipp Heckel
debba63a5d WIP DND override 2022-04-14 10:54:17 -04:00
211 changed files with 1321 additions and 12158 deletions

View file

@ -1,21 +0,0 @@
image: "registry.gitlab.e.foundation/e/os/docker-android-apps-cicd:latest"
stages:
- build
before_script:
- export GRADLE_USER_HOME=$(pwd)/.gradle
- chmod +x ./gradlew
cache:
key: ${CI_PROJECT_ID}
paths:
- .gradle/
buildRelease:
stage: build
script:
- ./gradlew assembleFdroid
artifacts:
paths:
- app/build/outputs/apk/fdroid/release

View file

@ -2,8 +2,32 @@
This is the Android app for [ntfy](https://github.com/binwiederhier/ntfy) ([ntfy.sh](https://ntfy.sh)). You can find the app in [F-Droid](https://f-droid.org/packages/io.heckel.ntfy/) or the [Play Store](https://play.google.com/store/apps/details?id=io.heckel.ntfy),
or as .apk files on the [releases page](https://github.com/binwiederhier/ntfy-android/releases).
## Build
For up-to-date building instructions, please see the [official docs](https://docs.ntfy.sh/develop/#android-app).
# Build
## Building without Firebase (F-Droid flavor)
Without Firebase, you may want to still change the default `app_base_url` in [strings.xml](https://github.com/binwiederhier/ntfy-android/blob/main/app/src/main/res/values/strings.xml)
if you're self-hosting the server. Then run:
```
# To build an unsigned .apk (app/build/outputs/apk/fdroid/*.apk)
./gradlew assembleFdroidRelease
# To build a bundle .aab (app/fdroid/release/*.aab)
./gradlew bundleFdroidRelease
```
## Building with Firebase (FCM, Google Play flavor)
To build your own version with Firebase, you must:
* Create a Firebase/FCM account
* Place your account file at `app/google-services.json`
* And change `app_base_url` in [strings.xml](https://github.com/binwiederhier/ntfy-android/blob/main/app/src/main/res/values/strings.xml)
* Then run:
```
# To build an unsigned .apk (app/build/outputs/apk/play/*.apk)
./gradlew assemblePlayRelease
# To build a bundle .aab (app/play/release/*.aab)
./gradlew bundlePlayRelease
```
## Translations
We're using [Weblate](https://hosted.weblate.org/projects/ntfy/) to translate the ntfy Android app. We'd love your participation.

View file

@ -1,21 +1,19 @@
repositories {
mavenCentral()
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'com.google.gms.google-services'
android {
compileSdkVersion 33
compileSdkVersion 31
defaultConfig {
applicationId "foundation.e.ntfy"
minSdkVersion 23
targetSdkVersion 33
applicationId "io.heckel.ntfy"
minSdkVersion 21
targetSdkVersion 31
versionCode 33
versionName "1.17.0"
versionCode 26
versionName "1.12.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@ -27,10 +25,6 @@ android {
}
}
buildFeatures {
viewBinding = true
}
buildTypes {
release {
minifyEnabled true
@ -48,12 +42,10 @@ 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,75 +56,46 @@ android {
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
freeCompilerArgs += [
'-Xjvm-default=all-compatibility' // https://stackoverflow.com/a/71234042/1440785
]
}
namespace "io.heckel.ntfy"
}
// 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.6.1"
implementation "androidx.core:core-ktx:1.10.1"
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
implementation "androidx.activity:activity-ktx:1.7.1"
implementation "androidx.fragment:fragment-ktx:1.5.7"
implementation "androidx.work:work-runtime-ktx:2.8.1"
implementation "androidx.appcompat:appcompat:1.4.1"
implementation "androidx.core:core-ktx:1.7.0"
implementation "androidx.constraintlayout:constraintlayout:2.1.3"
implementation "androidx.activity:activity-ktx:1.4.0"
implementation "androidx.fragment:fragment-ktx:1.4.1"
implementation "androidx.work:work-runtime-ktx:2.7.1"
implementation 'androidx.preference:preference-ktx:1.2.0'
// JSON serialization
implementation 'com.google.code.gson:gson:2.10'
implementation 'com.google.code.gson:gson:2.9.0'
// Room (SQLite)
def room_version = "2.5.1"
def room_version = "2.4.2"
implementation "androidx.room:room-ktx:$room_version"
kapt "androidx.room:room-compiler:$room_version"
// OkHttp (HTTP library)
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
// Firebase, sigh ... (only Google Play)
playImplementation 'com.google.firebase:firebase-messaging:23.1.2'
playImplementation 'com.google.firebase:firebase-messaging:23.0.2'
// RecyclerView
implementation "androidx.recyclerview:recyclerview:1.3.0"
implementation "androidx.recyclerview:recyclerview:1.3.0-alpha02"
// Swipe down to refresh
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
// Material design
implementation "com.google.android.material:material:1.9.0"
implementation "com.google.android.material:material:1.5.0"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.1"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1"
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
// Image viewer
implementation 'com.github.stfalcon-studio:StfalconImageViewer:v1.0.1'
implementation 'foundation.e:elib:0.0.1-alpha11'
}

View file

@ -1,302 +0,0 @@
{
"formatVersion": 1,
"database": {
"version": 10,
"identityHash": "c1b4f54d1d3111dc5c8f02e8fa960ceb",
"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, `upAppId` TEXT, `upConnectorToken` TEXT, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "baseUrl",
"columnName": "baseUrl",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "topic",
"columnName": "topic",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "instant",
"columnName": "instant",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "mutedUntil",
"columnName": "mutedUntil",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "upAppId",
"columnName": "upAppId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "upConnectorToken",
"columnName": "upConnectorToken",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [
{
"name": "index_Subscription_baseUrl_topic",
"unique": true,
"columnNames": [
"baseUrl",
"topic"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Subscription_baseUrl_topic` ON `${TABLE_NAME}` (`baseUrl`, `topic`)"
},
{
"name": "index_Subscription_upConnectorToken",
"unique": true,
"columnNames": [
"upConnectorToken"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Subscription_upConnectorToken` ON `${TABLE_NAME}` (`upConnectorToken`)"
}
],
"foreignKeys": []
},
{
"tableName": "Notification",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `title` TEXT NOT NULL, `message` TEXT NOT NULL, `encoding` TEXT NOT NULL, `notificationId` INTEGER NOT NULL, `priority` INTEGER NOT NULL DEFAULT 3, `tags` TEXT NOT NULL, `click` TEXT NOT NULL, `actions` TEXT, `deleted` INTEGER NOT NULL, `attachment_name` TEXT, `attachment_type` TEXT, `attachment_size` INTEGER, `attachment_expires` INTEGER, `attachment_url` TEXT, `attachment_contentUri` TEXT, `attachment_progress` INTEGER, PRIMARY KEY(`id`, `subscriptionId`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "subscriptionId",
"columnName": "subscriptionId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "message",
"columnName": "message",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "encoding",
"columnName": "encoding",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "notificationId",
"columnName": "notificationId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "priority",
"columnName": "priority",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "3"
},
{
"fieldPath": "tags",
"columnName": "tags",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "click",
"columnName": "click",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "actions",
"columnName": "actions",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "attachment.name",
"columnName": "attachment_name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.type",
"columnName": "attachment_type",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.size",
"columnName": "attachment_size",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "attachment.expires",
"columnName": "attachment_expires",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "attachment.url",
"columnName": "attachment_url",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.contentUri",
"columnName": "attachment_contentUri",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.progress",
"columnName": "attachment_progress",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id",
"subscriptionId"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "User",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`baseUrl` TEXT NOT NULL, `username` TEXT NOT NULL, `password` TEXT NOT NULL, PRIMARY KEY(`baseUrl`))",
"fields": [
{
"fieldPath": "baseUrl",
"columnName": "baseUrl",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "username",
"columnName": "username",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "password",
"columnName": "password",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"baseUrl"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "Log",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `tag` TEXT NOT NULL, `level` INTEGER NOT NULL, `message` TEXT NOT NULL, `exception` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "tag",
"columnName": "tag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "level",
"columnName": "level",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "message",
"columnName": "message",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "exception",
"columnName": "exception",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
}
],
"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, 'c1b4f54d1d3111dc5c8f02e8fa960ceb')"
]
}
}

View file

@ -1,320 +0,0 @@
{
"formatVersion": 1,
"database": {
"version": 11,
"identityHash": "31f8e6a2032d1d404fad4307abf23e1b",
"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, `icon` TEXT, `upAppId` TEXT, `upConnectorToken` TEXT, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "baseUrl",
"columnName": "baseUrl",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "topic",
"columnName": "topic",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "instant",
"columnName": "instant",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "mutedUntil",
"columnName": "mutedUntil",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minPriority",
"columnName": "minPriority",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "autoDelete",
"columnName": "autoDelete",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "icon",
"columnName": "icon",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "upAppId",
"columnName": "upAppId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "upConnectorToken",
"columnName": "upConnectorToken",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [
{
"name": "index_Subscription_baseUrl_topic",
"unique": true,
"columnNames": [
"baseUrl",
"topic"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Subscription_baseUrl_topic` ON `${TABLE_NAME}` (`baseUrl`, `topic`)"
},
{
"name": "index_Subscription_upConnectorToken",
"unique": true,
"columnNames": [
"upConnectorToken"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Subscription_upConnectorToken` ON `${TABLE_NAME}` (`upConnectorToken`)"
}
],
"foreignKeys": []
},
{
"tableName": "Notification",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `title` TEXT NOT NULL, `message` TEXT NOT NULL, `encoding` TEXT NOT NULL, `notificationId` INTEGER NOT NULL, `priority` INTEGER NOT NULL DEFAULT 3, `tags` TEXT NOT NULL, `click` TEXT NOT NULL, `actions` TEXT, `deleted` INTEGER NOT NULL, `attachment_name` TEXT, `attachment_type` TEXT, `attachment_size` INTEGER, `attachment_expires` INTEGER, `attachment_url` TEXT, `attachment_contentUri` TEXT, `attachment_progress` INTEGER, PRIMARY KEY(`id`, `subscriptionId`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "subscriptionId",
"columnName": "subscriptionId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "message",
"columnName": "message",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "encoding",
"columnName": "encoding",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "notificationId",
"columnName": "notificationId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "priority",
"columnName": "priority",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "3"
},
{
"fieldPath": "tags",
"columnName": "tags",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "click",
"columnName": "click",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "actions",
"columnName": "actions",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "attachment.name",
"columnName": "attachment_name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.type",
"columnName": "attachment_type",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.size",
"columnName": "attachment_size",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "attachment.expires",
"columnName": "attachment_expires",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "attachment.url",
"columnName": "attachment_url",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.contentUri",
"columnName": "attachment_contentUri",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.progress",
"columnName": "attachment_progress",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id",
"subscriptionId"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "User",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`baseUrl` TEXT NOT NULL, `username` TEXT NOT NULL, `password` TEXT NOT NULL, PRIMARY KEY(`baseUrl`))",
"fields": [
{
"fieldPath": "baseUrl",
"columnName": "baseUrl",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "username",
"columnName": "username",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "password",
"columnName": "password",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"baseUrl"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "Log",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `tag` TEXT NOT NULL, `level` INTEGER NOT NULL, `message` TEXT NOT NULL, `exception` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "tag",
"columnName": "tag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "level",
"columnName": "level",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "message",
"columnName": "message",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "exception",
"columnName": "exception",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
}
],
"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, '31f8e6a2032d1d404fad4307abf23e1b')"
]
}
}

View file

@ -1,344 +0,0 @@
{
"formatVersion": 1,
"database": {
"version": 12,
"identityHash": "d230005f4d9824ba9aa34c61003bdcbb",
"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, `displayName` TEXT, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "baseUrl",
"columnName": "baseUrl",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "topic",
"columnName": "topic",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "instant",
"columnName": "instant",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "mutedUntil",
"columnName": "mutedUntil",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minPriority",
"columnName": "minPriority",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "autoDelete",
"columnName": "autoDelete",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "lastNotificationId",
"columnName": "lastNotificationId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "icon",
"columnName": "icon",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "upAppId",
"columnName": "upAppId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "upConnectorToken",
"columnName": "upConnectorToken",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "displayName",
"columnName": "displayName",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [
{
"name": "index_Subscription_baseUrl_topic",
"unique": true,
"columnNames": [
"baseUrl",
"topic"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Subscription_baseUrl_topic` ON `${TABLE_NAME}` (`baseUrl`, `topic`)"
},
{
"name": "index_Subscription_upConnectorToken",
"unique": true,
"columnNames": [
"upConnectorToken"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Subscription_upConnectorToken` ON `${TABLE_NAME}` (`upConnectorToken`)"
}
],
"foreignKeys": []
},
{
"tableName": "Notification",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `title` TEXT NOT NULL, `message` TEXT NOT NULL, `encoding` TEXT NOT NULL, `notificationId` INTEGER NOT NULL, `priority` INTEGER NOT NULL DEFAULT 3, `tags` TEXT NOT NULL, `click` TEXT NOT NULL, `actions` TEXT, `deleted` INTEGER NOT NULL, `icon_url` TEXT, `icon_contentUri` TEXT, `attachment_name` TEXT, `attachment_type` TEXT, `attachment_size` INTEGER, `attachment_expires` INTEGER, `attachment_url` TEXT, `attachment_contentUri` TEXT, `attachment_progress` INTEGER, PRIMARY KEY(`id`, `subscriptionId`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "subscriptionId",
"columnName": "subscriptionId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "message",
"columnName": "message",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "encoding",
"columnName": "encoding",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "notificationId",
"columnName": "notificationId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "priority",
"columnName": "priority",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "3"
},
{
"fieldPath": "tags",
"columnName": "tags",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "click",
"columnName": "click",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "actions",
"columnName": "actions",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "icon.url",
"columnName": "icon_url",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "icon.contentUri",
"columnName": "icon_contentUri",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.name",
"columnName": "attachment_name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.type",
"columnName": "attachment_type",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.size",
"columnName": "attachment_size",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "attachment.expires",
"columnName": "attachment_expires",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "attachment.url",
"columnName": "attachment_url",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.contentUri",
"columnName": "attachment_contentUri",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.progress",
"columnName": "attachment_progress",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id",
"subscriptionId"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "User",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`baseUrl` TEXT NOT NULL, `username` TEXT NOT NULL, `password` TEXT NOT NULL, PRIMARY KEY(`baseUrl`))",
"fields": [
{
"fieldPath": "baseUrl",
"columnName": "baseUrl",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "username",
"columnName": "username",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "password",
"columnName": "password",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"baseUrl"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "Log",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `tag` TEXT NOT NULL, `level` INTEGER NOT NULL, `message` TEXT NOT NULL, `exception` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "tag",
"columnName": "tag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "level",
"columnName": "level",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "message",
"columnName": "message",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "exception",
"columnName": "exception",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
}
],
"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, 'd230005f4d9824ba9aa34c61003bdcbb')"
]
}
}

View file

@ -1,356 +0,0 @@
{
"formatVersion": 1,
"database": {
"version": 13,
"identityHash": "44fc291d937fdf02b9bc2d0abb10d2e0",
"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, `insistent` INTEGER NOT NULL, `lastNotificationId` TEXT, `icon` TEXT, `upAppId` TEXT, `upConnectorToken` TEXT, `displayName` TEXT, `dedicatedChannels` INTEGER NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "baseUrl",
"columnName": "baseUrl",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "topic",
"columnName": "topic",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "instant",
"columnName": "instant",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "mutedUntil",
"columnName": "mutedUntil",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minPriority",
"columnName": "minPriority",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "autoDelete",
"columnName": "autoDelete",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "insistent",
"columnName": "insistent",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "lastNotificationId",
"columnName": "lastNotificationId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "icon",
"columnName": "icon",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "upAppId",
"columnName": "upAppId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "upConnectorToken",
"columnName": "upConnectorToken",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "displayName",
"columnName": "displayName",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "dedicatedChannels",
"columnName": "dedicatedChannels",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [
{
"name": "index_Subscription_baseUrl_topic",
"unique": true,
"columnNames": [
"baseUrl",
"topic"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Subscription_baseUrl_topic` ON `${TABLE_NAME}` (`baseUrl`, `topic`)"
},
{
"name": "index_Subscription_upConnectorToken",
"unique": true,
"columnNames": [
"upConnectorToken"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Subscription_upConnectorToken` ON `${TABLE_NAME}` (`upConnectorToken`)"
}
],
"foreignKeys": []
},
{
"tableName": "Notification",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `title` TEXT NOT NULL, `message` TEXT NOT NULL, `encoding` TEXT NOT NULL, `notificationId` INTEGER NOT NULL, `priority` INTEGER NOT NULL DEFAULT 3, `tags` TEXT NOT NULL, `click` TEXT NOT NULL, `actions` TEXT, `deleted` INTEGER NOT NULL, `icon_url` TEXT, `icon_contentUri` TEXT, `attachment_name` TEXT, `attachment_type` TEXT, `attachment_size` INTEGER, `attachment_expires` INTEGER, `attachment_url` TEXT, `attachment_contentUri` TEXT, `attachment_progress` INTEGER, PRIMARY KEY(`id`, `subscriptionId`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "subscriptionId",
"columnName": "subscriptionId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "message",
"columnName": "message",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "encoding",
"columnName": "encoding",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "notificationId",
"columnName": "notificationId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "priority",
"columnName": "priority",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "3"
},
{
"fieldPath": "tags",
"columnName": "tags",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "click",
"columnName": "click",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "actions",
"columnName": "actions",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "icon.url",
"columnName": "icon_url",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "icon.contentUri",
"columnName": "icon_contentUri",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.name",
"columnName": "attachment_name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.type",
"columnName": "attachment_type",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.size",
"columnName": "attachment_size",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "attachment.expires",
"columnName": "attachment_expires",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "attachment.url",
"columnName": "attachment_url",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.contentUri",
"columnName": "attachment_contentUri",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.progress",
"columnName": "attachment_progress",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id",
"subscriptionId"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "User",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`baseUrl` TEXT NOT NULL, `username` TEXT NOT NULL, `password` TEXT NOT NULL, PRIMARY KEY(`baseUrl`))",
"fields": [
{
"fieldPath": "baseUrl",
"columnName": "baseUrl",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "username",
"columnName": "username",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "password",
"columnName": "password",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"baseUrl"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "Log",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `tag` TEXT NOT NULL, `level` INTEGER NOT NULL, `message` TEXT NOT NULL, `exception` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "tag",
"columnName": "tag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "level",
"columnName": "level",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "message",
"columnName": "message",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "exception",
"columnName": "exception",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
}
],
"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, '44fc291d937fdf02b9bc2d0abb10d2e0')"
]
}
}

View file

@ -1,6 +1,5 @@
package io.heckel.ntfy.firebase
@Suppress("UNUSED_PARAMETER")
class FirebaseMessenger {
fun subscribe(topic: String) {
// Dummy to keep F-Droid flavor happy

View file

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
package="io.heckel.ntfy">
<!-- Permissions -->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <!-- For instant delivery foregrounds service -->
@ -9,24 +8,16 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <!-- To restart service on reboot -->
<uses-permission android:name="android.permission.VIBRATE"/> <!-- Incoming notifications should be able to vibrate the phone -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28"/> <!-- Only required on SDK <= 28 -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/> <!-- To install packages downloaded through ntfy; craazyy! -->
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/> <!-- To reschedule the websocket retry -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <!-- As of Android 13, we need to ask for permission to post notifications -->
<!--
Permission REQUEST_INSTALL_PACKAGES (F-Droid only!):
- Permission is used to install .apk files that were received as attachments
- Google rejected the permission for ntfy, so this permission is STRIPPED OUT by the build process
for the Google Play variant of the app.
-->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" /> <!-- To override DND -->
<application
android:name=".app.Application"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:persistent="true"
android:roundIcon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:networkSecurityConfig="@xml/network_security_config"
@ -36,10 +27,11 @@
<activity
android:name=".ui.MainActivity"
android:label="@string/app_name"
android:excludeFromRecents="true"
android:exported="true">
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
@ -89,12 +81,6 @@
</intent-filter>
</activity>
<!-- Hack: Activity used for "view" action button with "clear=true" (to be able to cancel notifications and show a URL) -->
<activity
android:name=".msg.NotificationService$ViewActionWithClearActivity"
android:exported="false">
</activity>
<!-- Subscriber foreground service for hosts other than ntfy.sh -->
<service android:name=".service.SubscriberService"/>
@ -138,14 +124,7 @@
<!-- Broadcast receiver for the "Download"/"Cancel" attachment action in the notification popup -->
<receiver
android:name=".msg.NotificationService$UserActionBroadcastReceiver"
android:enabled="true"
android:exported="false">
</receiver>
<!-- Broadcast receiver for when the notification is swiped away (currently only to cancel the insistent sound) -->
<receiver
android:name=".msg.NotificationService$DeleteBroadcastReceiver"
android:name=".msg.NotificationService$DownloadBroadcastReceiver"
android:enabled="true"
android:exported="false">
</receiver>
@ -176,25 +155,5 @@
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
<activity
android:name=".ui.MainSettingsActivity"
android:theme="@style/PreferenceTheme"/>
<activity-alias
android:name=".ui.SettingsActivityLink"
android:exported="true"
android:label="@string/eos_settings_title"
android:targetActivity=".ui.MainSettingsActivity">
<intent-filter>
<action android:name="com.android.settings.action.EXTRA_SETTINGS" />
</intent-filter>
<meta-data
android:name="com.android.settings.category"
android:value="com.android.settings.category.device" />
<meta-data
android:name="com.android.settings.icon"
android:resource="@drawable/ic_notification" />
</activity-alias>
</application>
</manifest>

View file

@ -1,10 +1,16 @@
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
class Application : Application() {
private val database by lazy {
Log.init(this) // What a hack, but this is super early and used everywhere
Database.getInstance(this)
}
val repository by lazy {
val repository = Repository.getInstance(applicationContext)
if (repository.getRecordLogs()) {

View file

@ -5,11 +5,7 @@ import android.net.Uri
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.stream.JsonReader
import io.heckel.ntfy.R
import io.heckel.ntfy.app.Application
import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.firebase.FirebaseMessenger
import io.heckel.ntfy.msg.NotificationService
import io.heckel.ntfy.util.Log
import io.heckel.ntfy.util.topicUrl
import java.io.InputStreamReader
@ -18,8 +14,6 @@ class Backuper(val context: Context) {
private val gson = Gson()
private val resolver = context.applicationContext.contentResolver
private val repository = (context.applicationContext as Application).repository
private val messenger = FirebaseMessenger()
private val notifier = NotificationService(context)
suspend fun backup(uri: Uri, withSettings: Boolean = true, withSubscriptions: Boolean = true, withUsers: Boolean = true) {
Log.d(TAG, "Backing up settings to file $uri")
@ -90,40 +84,19 @@ class Backuper(val context: Context) {
private suspend fun applySubscriptions(subscriptions: List<Subscription>?) {
if (subscriptions == null) {
return
return;
}
val appBaseUrl = context.getString(R.string.app_base_url)
subscriptions.forEach { s ->
try {
// Add to database
val subscription = io.heckel.ntfy.db.Subscription(
repository.addSubscription(io.heckel.ntfy.db.Subscription(
id = s.id,
baseUrl = s.baseUrl,
topic = s.topic,
instant = s.instant,
dedicatedChannels = s.dedicatedChannels,
mutedUntil = s.mutedUntil,
minPriority = s.minPriority ?: Repository.MIN_PRIORITY_USE_GLOBAL,
autoDelete = s.autoDelete ?: Repository.AUTO_DELETE_USE_GLOBAL,
insistent = s.insistent ?: Repository.INSISTENT_MAX_PRIORITY_USE_GLOBAL,
lastNotificationId = s.lastNotificationId,
icon = s.icon,
upAppId = s.upAppId,
upConnectorToken = s.upConnectorToken,
displayName = s.displayName,
)
repository.addSubscription(subscription)
// Subscribe to Firebase topics
if (s.baseUrl == appBaseUrl) {
messenger.subscribe(s.topic)
}
// Create dedicated channels
if (s.dedicatedChannels) {
notifier.createSubscriptionNotificationChannels(subscription)
// TODO Backup/restore individual notification channel settings
}
upConnectorToken = s.upConnectorToken
))
} catch (e: Exception) {
Log.w(TAG, "Unable to restore subscription ${s.id} (${topicUrl(s.baseUrl, s.topic)}): ${e.message}. Ignoring.", e)
}
@ -132,30 +105,10 @@ class Backuper(val context: Context) {
private suspend fun applyNotifications(notifications: List<Notification>?) {
if (notifications == null) {
return
return;
}
notifications.forEach { n ->
try {
val actions = if (n.actions != null) {
n.actions.map { a ->
io.heckel.ntfy.db.Action(
id = a.id,
action = a.action,
label = a.label,
clear = a.clear,
url = a.url,
method = a.method,
headers = a.headers,
body = a.body,
intent = a.intent,
extras = a.extras,
progress = a.progress,
error = a.error
)
}
} else {
null
}
val attachment = if (n.attachment != null) {
io.heckel.ntfy.db.Attachment(
name = n.attachment.name,
@ -169,14 +122,6 @@ class Backuper(val context: Context) {
} else {
null
}
val icon = if (n.icon != null) {
io.heckel.ntfy.db.Icon(
url = n.icon.url,
contentUri = n.icon.contentUri,
)
} else {
null
}
repository.addNotification(io.heckel.ntfy.db.Notification(
id = n.id,
subscriptionId = n.subscriptionId,
@ -188,8 +133,6 @@ class Backuper(val context: Context) {
priority = n.priority,
tags = n.tags,
click = n.click,
icon = icon,
actions = actions,
attachment = attachment,
deleted = n.deleted
))
@ -201,7 +144,7 @@ class Backuper(val context: Context) {
private suspend fun applyUsers(users: List<User>?) {
if (users == null) {
return
return;
}
users.forEach { u ->
try {
@ -249,42 +192,15 @@ class Backuper(val context: Context) {
baseUrl = s.baseUrl,
topic = s.topic,
instant = s.instant,
dedicatedChannels = s.dedicatedChannels,
mutedUntil = s.mutedUntil,
minPriority = s.minPriority,
autoDelete = s.autoDelete,
insistent = s.insistent,
lastNotificationId = s.lastNotificationId,
icon = s.icon,
upAppId = s.upAppId,
upConnectorToken = s.upConnectorToken,
displayName = s.displayName
upConnectorToken = s.upConnectorToken
)
}
}
private suspend fun createNotificationList(): List<Notification> {
return repository.getNotifications().map { n ->
val actions = if (n.actions != null) {
n.actions.map { a ->
Action(
id = a.id,
action = a.action,
label = a.label,
clear = a.clear,
url = a.url,
method = a.method,
headers = a.headers,
body = a.body,
intent = a.intent,
extras = a.extras,
progress = a.progress,
error = a.error
)
}
} else {
null
}
val attachment = if (n.attachment != null) {
Attachment(
name = n.attachment.name,
@ -298,14 +214,6 @@ class Backuper(val context: Context) {
} else {
null
}
val icon = if (n.icon != null) {
Icon(
url = n.icon.url,
contentUri = n.icon.contentUri,
)
} else {
null
}
Notification(
id = n.id,
subscriptionId = n.subscriptionId,
@ -316,8 +224,6 @@ class Backuper(val context: Context) {
priority = n.priority,
tags = n.tags,
click = n.click,
icon = icon,
actions = actions,
attachment = attachment,
deleted = n.deleted
)
@ -335,6 +241,7 @@ class Backuper(val context: Context) {
}
companion object {
const val MIME_TYPE = "application/json"
private const val FILE_MAGIC = "ntfy2586"
private const val FILE_VERSION = 1
private const val TAG = "NtfyExporter"
@ -368,16 +275,9 @@ data class Subscription(
val baseUrl: String,
val topic: String,
val instant: Boolean,
val dedicatedChannels: Boolean,
val mutedUntil: Long,
val minPriority: Int?,
val autoDelete: Long?,
val insistent: Int?,
val lastNotificationId: String?,
val icon: String?,
val upAppId: String?,
val upConnectorToken: String?,
val displayName: String?
val upConnectorToken: String?
)
data class Notification(
@ -390,27 +290,10 @@ data class Notification(
val priority: Int, // 1=min, 3=default, 5=max
val tags: String,
val click: String, // URL/intent to open on notification click
val icon: Icon?,
val actions: List<Action>?,
val attachment: Attachment?,
val deleted: Boolean
)
data class Action(
val id: String, // Synthetic ID to identify result, and easily pass via Broadcast and WorkManager
val action: String, // "view", "http" or "broadcast"
val label: String,
val clear: Boolean?, // clear notification after successful execution
val url: String?, // used in "view" and "http" actions
val method: String?, // used in "http" action
val headers: Map<String,String>?, // used in "http" action
val body: String?, // used in "http" action
val intent: String?, // used in "broadcast" action
val extras: Map<String,String>?, // used in "broadcast" action
val progress: Int?, // used to indicate progress in popup
val error: String? // used to indicate errors in popup
)
data class Attachment(
val name: String, // Filename
val type: String?, // MIME type
@ -421,10 +304,6 @@ data class Attachment(
val progress: Int, // Progress during download, -1 if not downloaded
)
data class Icon(
val url: String, // URL (mandatory, see ntfy server)
val contentUri: String?, // After it's downloaded, the content:// location
)
data class User(
val baseUrl: String,

View file

@ -4,10 +4,8 @@ import android.content.Context
import androidx.room.*
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import io.heckel.ntfy.util.shortUrl
import kotlinx.coroutines.flow.Flow
import java.lang.reflect.Type
@Entity(indices = [Index(value = ["baseUrl", "topic"], unique = true), Index(value = ["upConnectorToken"], unique = true)])
data class Subscription(
@ -15,57 +13,17 @@ data class Subscription(
@ColumnInfo(name = "baseUrl") val baseUrl: String,
@ColumnInfo(name = "topic") val topic: String,
@ColumnInfo(name = "instant") val instant: Boolean,
@ColumnInfo(name = "mutedUntil") val mutedUntil: Long,
@ColumnInfo(name = "minPriority") val minPriority: Int,
@ColumnInfo(name = "autoDelete") val autoDelete: Long, // Seconds
@ColumnInfo(name = "insistent") val insistent: Int, // Ring constantly for max priority notifications (-1 = use global, 0 = off, 1 = on)
@ColumnInfo(name = "lastNotificationId") val lastNotificationId: String?, // Used for polling, with since=<id>
@ColumnInfo(name = "icon") val icon: String?, // content://-URI (or later other identifier)
@ColumnInfo(name = "mutedUntil") val mutedUntil: Long, // TODO notificationSound, notificationSchedule
@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?,
@ColumnInfo(name = "dedicatedChannels") val dedicatedChannels: Boolean,
// TODO autoDownloadAttachments, minPriority
@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,
insistent: Int,
lastNotificationId: String,
icon: String,
upAppId: String,
upConnectorToken: String,
displayName: String?,
dedicatedChannels: Boolean
) :
this(
id,
baseUrl,
topic,
instant,
mutedUntil,
minPriority,
autoDelete,
insistent,
lastNotificationId,
icon,
upAppId,
upConnectorToken,
displayName,
dedicatedChannels,
totalCount = 0,
newCount = 0,
lastActive = 0,
state = ConnectionState.NOT_APPLICABLE
)
constructor(id: Long, baseUrl: String, topic: String, instant: Boolean, mutedUntil: Long, upAppId: String, upConnectorToken: String) :
this(id, baseUrl, topic, instant, mutedUntil, upAppId, upConnectorToken, 0, 0, 0, ConnectionState.NOT_APPLICABLE)
}
enum class ConnectionState {
@ -78,15 +36,8 @@ data class SubscriptionWithMetadata(
val topic: String,
val instant: Boolean,
val mutedUntil: Long,
val autoDelete: Long,
val minPriority: Int,
val insistent: Int,
val lastNotificationId: String?,
val icon: String?,
val upAppId: String?,
val upConnectorToken: String?,
val displayName: String?,
val dedicatedChannels: Boolean,
val totalCount: Int,
val newCount: Int,
val lastActive: Long
@ -104,8 +55,6 @@ data class Notification(
@ColumnInfo(name = "priority", defaultValue = "3") val priority: Int, // 1=min, 3=default, 5=max
@ColumnInfo(name = "tags") val tags: String,
@ColumnInfo(name = "click") val click: String, // URL/intent to open on notification click
@Embedded(prefix = "icon_") val icon: Icon?,
@ColumnInfo(name = "actions") val actions: List<Action>?,
@Embedded(prefix = "attachment_") val attachment: Attachment?,
@ColumnInfo(name = "deleted") val deleted: Boolean,
)
@ -121,58 +70,14 @@ data class Attachment(
@ColumnInfo(name = "progress") val progress: Int, // Progress during download, -1 if not downloaded
) {
constructor(name: String, type: String?, size: Long?, expires: Long?, url: String) :
this(name, type, size, expires, url, null, ATTACHMENT_PROGRESS_NONE)
this(name, type, size, expires, url, null, PROGRESS_NONE)
}
const val ATTACHMENT_PROGRESS_NONE = -1
const val ATTACHMENT_PROGRESS_INDETERMINATE = -2
const val ATTACHMENT_PROGRESS_FAILED = -3
const val ATTACHMENT_PROGRESS_DELETED = -4
const val ATTACHMENT_PROGRESS_DONE = 100
@Entity
data class Icon(
@ColumnInfo(name = "url") val url: String, // URL (mandatory, see ntfy server)
@ColumnInfo(name = "contentUri") val contentUri: String?, // After it's downloaded, the content:// location
) {
constructor(url:String) :
this(url, null)
}
@Entity
data class Action(
@ColumnInfo(name = "id") val id: String, // Synthetic ID to identify result, and easily pass via Broadcast and WorkManager
@ColumnInfo(name = "action") val action: String, // "view", "http" or "broadcast"
@ColumnInfo(name = "label") val label: String,
@ColumnInfo(name = "clear") val clear: Boolean?, // clear notification after successful execution
@ColumnInfo(name = "url") val url: String?, // used in "view" and "http" actions
@ColumnInfo(name = "method") val method: String?, // used in "http" action
@ColumnInfo(name = "headers") val headers: Map<String,String>?, // used in "http" action
@ColumnInfo(name = "body") val body: String?, // used in "http" action
@ColumnInfo(name = "intent") val intent: String?, // used in "broadcast" action
@ColumnInfo(name = "extras") val extras: Map<String,String>?, // used in "broadcast" action
@ColumnInfo(name = "progress") val progress: Int?, // used to indicate progress in popup
@ColumnInfo(name = "error") val error: String?, // used to indicate errors in popup
)
const val ACTION_PROGRESS_ONGOING = 1
const val ACTION_PROGRESS_SUCCESS = 2
const val ACTION_PROGRESS_FAILED = 3
class Converters {
private val gson = Gson()
@TypeConverter
fun toActionList(value: String?): List<Action>? {
val listType: Type = object : TypeToken<List<Action>?>() {}.type
return gson.fromJson(value, listType)
}
@TypeConverter
fun fromActionList(list: List<Action>?): String {
return gson.toJson(list)
}
}
const val PROGRESS_NONE = -1
const val PROGRESS_INDETERMINATE = -2
const val PROGRESS_FAILED = -3
const val PROGRESS_DELETED = -4
const val PROGRESS_DONE = 100
@Entity
data class User(
@ -196,8 +101,7 @@ data class LogEntry(
this(0, timestamp, tag, level, message, exception)
}
@androidx.room.Database(entities = [Subscription::class, Notification::class, User::class, LogEntry::class], version = 13)
@TypeConverters(Converters::class)
@androidx.room.Database(entities = [Subscription::class, Notification::class, User::class, LogEntry::class], version = 9)
abstract class Database : RoomDatabase() {
abstract fun subscriptionDao(): SubscriptionDao
abstract fun notificationDao(): NotificationDao
@ -220,10 +124,6 @@ abstract class Database : RoomDatabase() {
.addMigrations(MIGRATION_6_7)
.addMigrations(MIGRATION_7_8)
.addMigrations(MIGRATION_8_9)
.addMigrations(MIGRATION_9_10)
.addMigrations(MIGRATION_10_11)
.addMigrations(MIGRATION_11_12)
.addMigrations(MIGRATION_12_13)
.fallbackToDestructiveMigration()
.build()
this.instance = instance
@ -299,36 +199,6 @@ abstract class Database : RoomDatabase() {
db.execSQL("ALTER TABLE Notification ADD COLUMN encoding TEXT NOT NULL DEFAULT('')")
}
}
private val MIGRATION_9_10 = object : Migration(9, 10) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Notification ADD COLUMN actions TEXT")
}
}
private val MIGRATION_10_11 = object : Migration(10, 11) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Subscription ADD COLUMN minPriority INT NOT NULL DEFAULT (0)") // = Repository.MIN_PRIORITY_USE_GLOBAL
db.execSQL("ALTER TABLE Subscription ADD COLUMN autoDelete INT NOT NULL DEFAULT (-1)") // = Repository.AUTO_DELETE_USE_GLOBAL
db.execSQL("ALTER TABLE Subscription ADD COLUMN icon TEXT")
}
}
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")
db.execSQL("ALTER TABLE Notification ADD COLUMN icon_url TEXT") // Room limitation: Has to be nullable for @Embedded
db.execSQL("ALTER TABLE Notification ADD COLUMN icon_contentUri TEXT")
}
}
private val MIGRATION_12_13 = object : Migration(12, 13) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Subscription ADD COLUMN insistent INTEGER NOT NULL DEFAULT (-1)") // = Repository.INSISTENT_MAX_PRIORITY_USE_GLOBAL
db.execSQL("ALTER TABLE Subscription ADD COLUMN dedicatedChannels INTEGER NOT NULL DEFAULT (0)")
}
}
}
}
@ -336,7 +206,7 @@ abstract class Database : RoomDatabase() {
interface SubscriptionDao {
@Query("""
SELECT
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.insistent, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken, s.displayName, s.dedicatedChannels,
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.upAppId, s.upConnectorToken,
COUNT(n.id) totalCount,
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
IFNULL(MAX(n.timestamp),0) AS lastActive
@ -349,7 +219,7 @@ interface SubscriptionDao {
@Query("""
SELECT
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.insistent, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken, s.displayName, s.dedicatedChannels,
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.upAppId, s.upConnectorToken,
COUNT(n.id) totalCount,
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
IFNULL(MAX(n.timestamp),0) AS lastActive
@ -362,7 +232,7 @@ interface SubscriptionDao {
@Query("""
SELECT
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.insistent, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken, s.displayName, s.dedicatedChannels,
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.upAppId, s.upConnectorToken,
COUNT(n.id) totalCount,
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
IFNULL(MAX(n.timestamp),0) AS lastActive
@ -375,7 +245,7 @@ interface SubscriptionDao {
@Query("""
SELECT
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.insistent, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken, s.displayName, s.dedicatedChannels,
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.upAppId, s.upConnectorToken,
COUNT(n.id) totalCount,
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
IFNULL(MAX(n.timestamp),0) AS lastActive
@ -388,7 +258,7 @@ interface SubscriptionDao {
@Query("""
SELECT
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.insistent, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken, s.displayName, s.dedicatedChannels,
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.upAppId, s.upConnectorToken,
COUNT(n.id) totalCount,
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
IFNULL(MAX(n.timestamp),0) AS lastActive
@ -405,9 +275,6 @@ interface SubscriptionDao {
@Update
fun update(subscription: Subscription)
@Query("UPDATE subscription SET lastNotificationId = :lastNotificationId WHERE id = :subscriptionId")
fun updateLastNotificationId(subscriptionId: Long, lastNotificationId: String)
@Query("DELETE FROM subscription WHERE id = :subscriptionId")
fun remove(subscriptionId: Long)
}
@ -426,12 +293,6 @@ interface NotificationDao {
@Query("SELECT * FROM notification WHERE deleted = 1 AND attachment_contentUri <> ''")
fun listDeletedWithAttachments(): List<Notification>
@Query("SELECT DISTINCT icon_contentUri FROM notification WHERE deleted != 1 AND icon_contentUri <> ''")
fun listActiveIconUris(): List<String>
@Query("UPDATE notification SET icon_contentUri = null WHERE icon_contentUri = :uri")
fun clearIconUri(uri: String)
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun add(notification: Notification)
@ -450,14 +311,14 @@ interface NotificationDao {
@Query("UPDATE notification SET deleted = 1 WHERE subscriptionId = :subscriptionId")
fun markAllAsDeleted(subscriptionId: Long)
@Query("UPDATE notification SET deleted = 1 WHERE subscriptionId = :subscriptionId AND timestamp < :olderThanTimestamp")
fun markAsDeletedIfOlderThan(subscriptionId: Long, olderThanTimestamp: Long)
@Query("UPDATE notification SET deleted = 1 WHERE timestamp < :olderThanTimestamp")
fun markAsDeletedIfOlderThan(olderThanTimestamp: Long)
@Query("UPDATE notification SET deleted = 0 WHERE id = :notificationId")
fun undelete(notificationId: String)
@Query("DELETE FROM notification WHERE subscriptionId = :subscriptionId AND timestamp < :olderThanTimestamp")
fun removeIfOlderThan(subscriptionId: Long, olderThanTimestamp: Long)
@Query("DELETE FROM notification WHERE timestamp < :olderThanTimestamp")
fun removeIfOlderThan(olderThanTimestamp: Long)
@Query("DELETE FROM notification WHERE subscriptionId = :subscriptionId")
fun removeAll(subscriptionId: Long)

View file

@ -2,7 +2,6 @@ package io.heckel.ntfy.db
import android.content.Context
import android.content.SharedPreferences
import android.media.MediaPlayer
import android.os.Build
import androidx.annotation.WorkerThread
import androidx.appcompat.app.AppCompatDelegate
@ -19,10 +18,7 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
private val connectionStates = ConcurrentHashMap<Long, ConnectionState>()
private val connectionStatesLiveData = MutableLiveData(connectionStates)
// TODO Move these into an ApplicationState singleton
val detailViewSubscriptionId = AtomicLong(0L) // Omg, what a hack ...
val mediaPlayer = MediaPlayer()
init {
Log.d(TAG, "Created $this")
@ -96,14 +92,6 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
return notificationDao.listDeletedWithAttachments()
}
fun getActiveIconUris(): Set<String> {
return notificationDao.listActiveIconUris().toSet()
}
fun clearIconUri(uri: String) {
notificationDao.clearIconUri(uri)
}
fun getNotificationsLiveData(subscriptionId: Long): LiveData<List<Notification>> {
return notificationDao.listFlow(subscriptionId).asLiveData()
}
@ -128,7 +116,6 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
if (maybeExistingNotification != null) {
return false
}
subscriptionDao.updateLastNotificationId(notification.subscriptionId, notification.id)
notificationDao.add(notification)
return true
}
@ -149,12 +136,12 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
notificationDao.markAllAsDeleted(subscriptionId)
}
fun markAsDeletedIfOlderThan(subscriptionId: Long, olderThanTimestamp: Long) {
notificationDao.markAsDeletedIfOlderThan(subscriptionId, olderThanTimestamp)
fun markAsDeletedIfOlderThan(olderThanTimestamp: Long) {
notificationDao.markAsDeletedIfOlderThan(olderThanTimestamp)
}
fun removeNotificationsIfOlderThan(subscriptionId: Long, olderThanTimestamp: Long) {
notificationDao.removeIfOlderThan(subscriptionId, olderThanTimestamp)
fun removeNotificationsIfOlderThan(olderThanTimestamp: Long) {
notificationDao.removeIfOlderThan(olderThanTimestamp)
}
fun removeAllNotifications(subscriptionId: Long) {
@ -216,7 +203,7 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
}
fun setMinPriority(minPriority: Int) {
if (minPriority <= MIN_PRIORITY_ANY) {
if (minPriority <= 1) {
sharedPrefs.edit()
.remove(SHARED_PREFS_MIN_PRIORITY)
.apply()
@ -228,7 +215,12 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
}
fun getMinPriority(): Int {
return sharedPrefs.getInt(SHARED_PREFS_MIN_PRIORITY, MIN_PRIORITY_ANY)
return sharedPrefs.getInt(SHARED_PREFS_MIN_PRIORITY, 1) // 1/low means all priorities
}
fun getDnsOverridePriority(): Int {
return sharedPrefs.getInt(SHARED_PREFS_DND_OVERRIDE_PRIORITY, 5)
}
fun getAutoDownloadMaxSize(): Long {
@ -292,26 +284,6 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
.apply()
}
fun getUnifiedPushEnabled(): Boolean {
return sharedPrefs.getBoolean(SHARED_PREFS_UNIFIEDPUSH_ENABLED, true) // Enabled by default
}
fun setUnifiedPushEnabled(enabled: Boolean) {
sharedPrefs.edit()
.putBoolean(SHARED_PREFS_UNIFIEDPUSH_ENABLED, enabled)
.apply()
}
fun getInsistentMaxPriorityEnabled(): Boolean {
return sharedPrefs.getBoolean(SHARED_PREFS_INSISTENT_MAX_PRIORITY_ENABLED, false) // Disabled by default
}
fun setInsistentMaxPriorityEnabled(enabled: Boolean) {
sharedPrefs.edit()
.putBoolean(SHARED_PREFS_INSISTENT_MAX_PRIORITY_ENABLED, enabled)
.apply()
}
fun getRecordLogs(): Boolean {
return sharedPrefs.getBoolean(SHARED_PREFS_RECORD_LOGS_ENABLED, false) // Disabled by default
}
@ -332,13 +304,13 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
.apply()
}
fun getWebSocketRemindTime(): Long {
return sharedPrefs.getLong(SHARED_PREFS_WEBSOCKET_REMIND_TIME, WEBSOCKET_REMIND_TIME_ALWAYS)
fun getJsonStreamRemindTime(): Long {
return sharedPrefs.getLong(SHARED_PREFS_JSON_STREAM_REMIND_TIME, JSON_STREAM_REMIND_TIME_ALWAYS)
}
fun setWebSocketRemindTime(timeMillis: Long) {
fun setJsonStreamRemindTime(timeMillis: Long) {
sharedPrefs.edit()
.putLong(SHARED_PREFS_WEBSOCKET_REMIND_TIME, timeMillis)
.putLong(SHARED_PREFS_JSON_STREAM_REMIND_TIME, timeMillis)
.apply()
}
@ -409,16 +381,9 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
baseUrl = s.baseUrl,
topic = s.topic,
instant = s.instant,
dedicatedChannels = s.dedicatedChannels,
mutedUntil = s.mutedUntil,
minPriority = s.minPriority,
autoDelete = s.autoDelete,
insistent = s.insistent,
lastNotificationId = s.lastNotificationId,
icon = s.icon,
upAppId = s.upAppId,
upConnectorToken = s.upConnectorToken,
displayName = s.displayName,
totalCount = s.totalCount,
newCount = s.newCount,
lastActive = s.lastActive,
@ -436,16 +401,9 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
baseUrl = s.baseUrl,
topic = s.topic,
instant = s.instant,
dedicatedChannels = s.dedicatedChannels,
mutedUntil = s.mutedUntil,
minPriority = s.minPriority,
autoDelete = s.autoDelete,
insistent = s.insistent,
lastNotificationId = s.lastNotificationId,
icon = s.icon,
upAppId = s.upAppId,
upConnectorToken = s.upConnectorToken,
displayName = s.displayName,
totalCount = s.totalCount,
newCount = s.newCount,
lastActive = s.lastActive,
@ -482,25 +440,21 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
const val SHARED_PREFS_AUTO_RESTART_WORKER_VERSION = "AutoRestartWorkerVersion"
const val SHARED_PREFS_MUTED_UNTIL_TIMESTAMP = "MutedUntil"
const val SHARED_PREFS_MIN_PRIORITY = "MinPriority"
const val SHARED_PREFS_DND_OVERRIDE_PRIORITY = "DndOverridePriority"
const val SHARED_PREFS_AUTO_DOWNLOAD_MAX_SIZE = "AutoDownload"
const val SHARED_PREFS_AUTO_DELETE_SECONDS = "AutoDelete"
const val SHARED_PREFS_CONNECTION_PROTOCOL = "ConnectionProtocol"
const val SHARED_PREFS_DARK_MODE = "DarkMode"
const val SHARED_PREFS_BROADCAST_ENABLED = "BroadcastEnabled"
const val SHARED_PREFS_UNIFIEDPUSH_ENABLED = "UnifiedPushEnabled"
const val SHARED_PREFS_INSISTENT_MAX_PRIORITY_ENABLED = "InsistentMaxPriority"
const val SHARED_PREFS_RECORD_LOGS_ENABLED = "RecordLogs"
const val SHARED_PREFS_BATTERY_OPTIMIZATIONS_REMIND_TIME = "BatteryOptimizationsRemindTime"
const val SHARED_PREFS_WEBSOCKET_REMIND_TIME = "JsonStreamRemindTime" // "Use WebSocket" banner (used to be JSON stream deprecation banner)
const val SHARED_PREFS_JSON_STREAM_REMIND_TIME = "JsonStreamRemindTime" // Deprecation of JSON stream
const val SHARED_PREFS_UNIFIED_PUSH_BASE_URL = "UnifiedPushBaseURL" // Legacy key required for migration to DefaultBaseURL
const val SHARED_PREFS_DEFAULT_BASE_URL = "DefaultBaseURL"
const val SHARED_PREFS_LAST_TOPICS = "LastTopics"
private const val LAST_TOPICS_COUNT = 3
const val MIN_PRIORITY_USE_GLOBAL = 0
const val MIN_PRIORITY_ANY = 1
const val MUTED_UNTIL_SHOW_ALL = 0L
const val MUTED_UNTIL_FOREVER = 1L
const val MUTED_UNTIL_TOMORROW = 2L
@ -511,8 +465,7 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
const val AUTO_DOWNLOAD_DEFAULT = ONE_MB
private const val ONE_DAY_SECONDS = 24 * 60 * 60L
const val AUTO_DELETE_USE_GLOBAL = -1L // Values must match values.xml
const val AUTO_DELETE_NEVER = 0L
const val AUTO_DELETE_NEVER = 0L // Values must match values.xml
const val AUTO_DELETE_ONE_DAY_SECONDS = ONE_DAY_SECONDS
const val AUTO_DELETE_THREE_DAYS_SECONDS = 3 * ONE_DAY_SECONDS
const val AUTO_DELETE_ONE_WEEK_SECONDS = 7 * ONE_DAY_SECONDS
@ -520,17 +473,14 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
const val AUTO_DELETE_THREE_MONTHS_SECONDS = 90 * ONE_DAY_SECONDS
const val AUTO_DELETE_DEFAULT_SECONDS = AUTO_DELETE_ONE_MONTH_SECONDS
const val INSISTENT_MAX_PRIORITY_USE_GLOBAL = -1 // Values must match values.xml
const val INSISTENT_MAX_PRIORITY_ENABLED = 1 // 0 = Disabled (but not needed in code)
const val CONNECTION_PROTOCOL_JSONHTTP = "jsonhttp"
const val CONNECTION_PROTOCOL_WS = "ws"
const val BATTERY_OPTIMIZATIONS_REMIND_TIME_ALWAYS = 1L
const val BATTERY_OPTIMIZATIONS_REMIND_TIME_NEVER = Long.MAX_VALUE
const val WEBSOCKET_REMIND_TIME_ALWAYS = 1L
const val WEBSOCKET_REMIND_TIME_NEVER = Long.MAX_VALUE
const val JSON_STREAM_REMIND_TIME_ALWAYS = 1L
const val JSON_STREAM_REMIND_TIME_NEVER = Long.MAX_VALUE
private const val TAG = "NtfyRepository"
private var instance: Repository? = null

View file

@ -1,5 +1,6 @@
package io.heckel.ntfy.msg
import android.net.Uri
import android.os.Build
import io.heckel.ntfy.BuildConfig
import io.heckel.ntfy.db.Notification
@ -8,6 +9,7 @@ import io.heckel.ntfy.util.*
import okhttp3.*
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.IOException
import java.net.URL
import java.net.URLEncoder
import java.nio.charset.StandardCharsets.UTF_8
import java.util.concurrent.TimeUnit
@ -37,7 +39,7 @@ class ApiService {
user: User? = null,
message: String,
title: String = "",
priority: Int = PRIORITY_DEFAULT,
priority: Int = 3,
tags: List<String> = emptyList(),
delay: String = "",
body: RequestBody? = null,
@ -45,7 +47,7 @@ class ApiService {
) {
val url = topicUrl(baseUrl, topic)
val query = mutableListOf<String>()
if (priority in ALL_PRIORITIES) {
if (priority in 1..5) {
query.add("priority=$priority")
}
if (tags.isNotEmpty()) {
@ -84,8 +86,8 @@ class ApiService {
}
}
fun poll(subscriptionId: Long, baseUrl: String, topic: String, user: User?, since: String? = null): List<Notification> {
val sinceVal = since ?: "all"
fun poll(subscriptionId: Long, baseUrl: String, topic: String, user: User?, since: Long = 0L): List<Notification> {
val sinceVal = if (since == 0L) "all" else since.toString()
val url = topicUrlJsonPoll(baseUrl, topic, sinceVal)
Log.d(TAG, "Polling topic $url")
@ -95,7 +97,7 @@ class ApiService {
throw Exception("Unexpected response ${response.code} when polling topic $url")
}
val body = response.body?.string()?.trim()
if (body.isNullOrEmpty()) return emptyList()
if (body == null || body.isEmpty()) return emptyList()
val notifications = body.lines().mapNotNull { line ->
parser.parse(line, subscriptionId = subscriptionId, notificationId = 0) // No notification when we poll
}
@ -108,16 +110,15 @@ class ApiService {
fun subscribe(
baseUrl: String,
topics: String,
unifiedPushTopics: String,
since: String?,
since: Long,
user: User?,
notify: (topic: String, Notification) -> Unit,
fail: (Exception) -> Unit
): Call {
val sinceVal = since ?: "all"
val sinceVal = if (since == 0L) "all" else since.toString()
val url = topicUrlJson(baseUrl, topics, sinceVal)
Log.d(TAG, "Opening subscription connection to $url")
val request = requestBuilder(url, user, unifiedPushTopics).build()
val request = requestBuilder(url, user).build()
val call = subscriberClient.newCall(request)
call.enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
@ -167,7 +168,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})"
@ -179,16 +180,13 @@ class ApiService {
const val EVENT_KEEPALIVE = "keepalive"
const val EVENT_POLL_REQUEST = "poll_request"
fun requestBuilder(url: String, user: User?, unifiedPushTopics: String? = null): Request.Builder {
fun requestBuilder(url: String, user: User?): Request.Builder {
val builder = Request.Builder()
.url(url)
.addHeader("User-Agent", USER_AGENT)
if (user != null) {
builder.addHeader("Authorization", Credentials.basic(user.username, user.password, UTF_8))
}
if (unifiedPushTopics != null) {
builder.addHeader("Rate-Topics", unifiedPushTopics)
}
return builder
}
}

View file

@ -2,8 +2,8 @@ package io.heckel.ntfy.msg
import android.content.Context
import android.content.Intent
import android.util.Base64
import io.heckel.ntfy.R
import io.heckel.ntfy.db.Action
import io.heckel.ntfy.db.Notification
import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.db.Subscription
@ -17,7 +17,7 @@ import kotlinx.coroutines.launch
* in order to facilitate tasks app integrations.
*/
class BroadcastService(private val ctx: Context) {
fun sendMessage(subscription: Subscription, notification: Notification, muted: Boolean) {
fun send(subscription: Subscription, notification: Notification, muted: Boolean) {
val intent = Intent()
intent.action = MESSAGE_RECEIVED_ACTION
intent.putExtra("id", notification.id)
@ -31,26 +31,10 @@ class BroadcastService(private val ctx: Context) {
intent.putExtra("tags", notification.tags)
intent.putExtra("tags_map", joinTagsMap(splitTags(notification.tags)))
intent.putExtra("priority", notification.priority)
intent.putExtra("click", notification.click)
intent.putExtra("muted", muted)
intent.putExtra("muted_str", muted.toString())
intent.putExtra("attachment_name", notification.attachment?.name ?: "")
intent.putExtra("attachment_type", notification.attachment?.type ?: "")
intent.putExtra("attachment_size", notification.attachment?.size ?: 0L)
intent.putExtra("attachment_expires", notification.attachment?.expires ?: 0L)
intent.putExtra("attachment_url", notification.attachment?.url ?: "")
Log.d(TAG, "Sending message intent broadcast: ${intent.action} with extras ${intent.extras}")
ctx.sendBroadcast(intent)
}
fun sendUserAction(action: Action) {
val intent = Intent()
intent.action = action.intent ?: USER_ACTION_ACTION
action.extras?.forEach { (key, value) ->
intent.putExtra(key, value)
}
Log.d(TAG, "Sending user action intent broadcast: ${intent.action} with extras ${intent.extras}")
Log.d(TAG, "Sending intent broadcast: $intent")
ctx.sendBroadcast(intent)
}
@ -125,6 +109,5 @@ class BroadcastService(private val ctx: Context) {
// These constants cannot be changed without breaking the contract; also see manifest
private const val MESSAGE_RECEIVED_ACTION = "io.heckel.ntfy.MESSAGE_RECEIVED"
private const val MESSAGE_SEND_ACTION = "io.heckel.ntfy.SEND_MESSAGE"
private const val USER_ACTION_ACTION = "io.heckel.ntfy.USER_ACTION"
}
}

View file

@ -1,168 +0,0 @@
package io.heckel.ntfy.msg
import android.content.Context
import android.net.Uri
import androidx.core.content.FileProvider
import androidx.work.Worker
import androidx.work.WorkerParameters
import io.heckel.ntfy.BuildConfig
import io.heckel.ntfy.app.Application
import io.heckel.ntfy.db.*
import io.heckel.ntfy.util.Log
import io.heckel.ntfy.util.sha256
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import java.io.File
import java.util.Date
import java.util.concurrent.TimeUnit
class DownloadIconWorker(private val context: Context, params: WorkerParameters) : Worker(context, params) {
private val client = OkHttpClient.Builder()
.callTimeout(1, TimeUnit.MINUTES) // Total timeout for entire request
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.build()
private val notifier = NotificationService(context)
private lateinit var repository: Repository
private lateinit var subscription: Subscription
private lateinit var notification: Notification
private lateinit var icon: Icon
private var uri: Uri? = null
override fun doWork(): Result {
if (context.applicationContext !is Application) return Result.failure()
val notificationId = inputData.getString(INPUT_DATA_ID) ?: return Result.failure()
val app = context.applicationContext as Application
repository = app.repository
notification = repository.getNotification(notificationId) ?: return Result.failure()
subscription = repository.getSubscription(notification.subscriptionId) ?: return Result.failure()
icon = notification.icon ?: return Result.failure()
try {
val iconFile = createIconFile(icon)
val yesterdayTimestamp = Date().time - MAX_CACHE_MILLIS
if (!iconFile.exists() || iconFile.lastModified() < yesterdayTimestamp) {
downloadIcon(iconFile)
} else {
Log.d(TAG, "Loading icon from cache: $iconFile")
val iconUri = createIconUri(iconFile)
this.uri = iconUri // Required for cleanup in onStopped()
save(icon.copy(contentUri = iconUri.toString()))
}
} catch (e: Exception) {
failed(e)
}
return Result.success()
}
override fun onStopped() {
Log.d(TAG, "Icon download was canceled")
maybeDeleteFile()
}
private fun downloadIcon(iconFile: File) {
Log.d(TAG, "Downloading icon from ${icon.url}")
try {
val request = Request.Builder()
.url(icon.url)
.addHeader("User-Agent", ApiService.USER_AGENT)
.build()
client.newCall(request).execute().use { response ->
Log.d(TAG, "Headers received: $response, Content-Length: ${response.headers["Content-Length"]}")
if (!response.isSuccessful || response.body == null) {
throw Exception("Unexpected response: ${response.code}")
} else if (shouldAbortDownload(response)) {
Log.d(TAG, "Aborting download: Content-Length is larger than auto-download setting")
return
}
val resolver = applicationContext.contentResolver
val uri = createIconUri(iconFile)
this.uri = uri // Required for cleanup in onStopped()
Log.d(TAG, "Starting download to content URI: $uri")
var bytesCopied: Long = 0
val outFile = resolver.openOutputStream(uri) ?: throw Exception("Cannot open output stream")
val downloadLimit = getDownloadLimit()
outFile.use { fileOut ->
val fileIn = response.body!!.byteStream()
val buffer = ByteArray(BUFFER_SIZE)
var bytes = fileIn.read(buffer)
while (bytes >= 0) {
if (bytesCopied > downloadLimit) {
throw Exception("Icon is longer than max download size.")
}
fileOut.write(buffer, 0, bytes)
bytesCopied += bytes
bytes = fileIn.read(buffer)
}
}
Log.d(TAG, "Icon download: successful response, proceeding with download")
save(icon.copy(contentUri = uri.toString()))
}
} catch (e: Exception) {
failed(e)
}
}
private fun failed(e: Exception) {
Log.w(TAG, "Icon download failed", e)
maybeDeleteFile()
}
private fun maybeDeleteFile() {
val uriCopy = uri
if (uriCopy != null) {
Log.d(TAG, "Deleting leftover icon $uriCopy")
val resolver = applicationContext.contentResolver
resolver.delete(uriCopy, null, null)
}
}
private fun save(newIcon: Icon) {
Log.d(TAG, "Updating icon: $newIcon")
icon = newIcon
notification = notification.copy(icon = newIcon)
notifier.update(subscription, notification)
repository.updateNotification(notification)
}
private fun shouldAbortDownload(response: Response): Boolean {
val maxAutoDownloadSize = getDownloadLimit()
val size = response.headers["Content-Length"]?.toLongOrNull() ?: return false // Don't abort here if size unknown
return size > maxAutoDownloadSize
}
private fun getDownloadLimit(): Long {
return if (repository.getAutoDownloadMaxSize() != Repository.AUTO_DOWNLOAD_NEVER && repository.getAutoDownloadMaxSize() != Repository.AUTO_DOWNLOAD_ALWAYS) {
Math.min(repository.getAutoDownloadMaxSize(), MAX_ICON_DOWNLOAD_BYTES)
} else {
DEFAULT_MAX_ICON_DOWNLOAD_BYTES
}
}
private fun createIconFile(icon: Icon): File {
val iconDir = File(context.cacheDir, ICON_CACHE_DIR)
if (!iconDir.exists() && !iconDir.mkdirs()) {
throw Exception("Cannot create cache directory for icons: $iconDir")
}
val hash = icon.url.sha256()
return File(iconDir, hash)
}
private fun createIconUri(iconFile: File): Uri {
return FileProvider.getUriForFile(context, FILE_PROVIDER_AUTHORITY, iconFile)
}
companion object {
const val INPUT_DATA_ID = "id"
const val FILE_PROVIDER_AUTHORITY = BuildConfig.APPLICATION_ID + ".provider" // See AndroidManifest.xml
const val DEFAULT_MAX_ICON_DOWNLOAD_BYTES = 307_200L // 300 KB
const val MAX_ICON_DOWNLOAD_BYTES = 5_242_880L // 5 MB
const val MAX_CACHE_MILLIS = 1000*60*60*24 // 24 hours
const val ICON_CACHE_DIR = "icons"
private const val TAG = "NtfyIconDownload"
private const val BUFFER_SIZE = 8 * 1024
}
}

View file

@ -11,77 +11,32 @@ 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"
private const val DOWNLOAD_WORK_ATTACHMENT_NAME_PREFIX = "io.heckel.ntfy.DOWNLOAD_FILE_"
private const val DOWNLOAD_WORK_ICON_NAME_PREFIX = "io.heckel.ntfy.DOWNLOAD_ICON_"
private const val DOWNLOAD_WORK_BOTH_NAME_PREFIX = "io.heckel.ntfy.DOWNLOAD_BOTH_"
class DownloadManager {
companion object {
private const val TAG = "NtfyDownloadManager"
private const val DOWNLOAD_WORK_NAME_PREFIX = "io.heckel.ntfy.DOWNLOAD_FILE_"
fun enqueue(context: Context, notificationId: String, userAction: Boolean, type: DownloadType) {
when (type) {
DownloadType.ATTACHMENT -> enqueueAttachment(context, notificationId, userAction)
DownloadType.ICON -> enqueueIcon(context, notificationId)
DownloadType.BOTH -> enqueueAttachmentAndIcon(context, notificationId, userAction)
fun enqueue(context: Context, notificationId: String, userAction: Boolean) {
val workManager = WorkManager.getInstance(context)
val workName = DOWNLOAD_WORK_NAME_PREFIX + notificationId
Log.d(TAG,"Enqueuing work to download attachment for notification $notificationId, work: $workName")
val workRequest = OneTimeWorkRequest.Builder(DownloadWorker::class.java)
.setInputData(workDataOf(
DownloadWorker.INPUT_DATA_ID to notificationId,
DownloadWorker.INPUT_DATA_USER_ACTION to userAction
))
.build()
workManager.enqueueUniqueWork(workName, ExistingWorkPolicy.KEEP, workRequest)
}
}
private fun enqueueAttachment(context: Context, notificationId: String, userAction: Boolean) {
val workManager = WorkManager.getInstance(context)
val workName = DOWNLOAD_WORK_ATTACHMENT_NAME_PREFIX + notificationId
Log.d(TAG,"Enqueuing work to download attachment for notification $notificationId, work: $workName")
val workRequest = OneTimeWorkRequest.Builder(DownloadAttachmentWorker::class.java)
.setInputData(workDataOf(
DownloadAttachmentWorker.INPUT_DATA_ID to notificationId,
DownloadAttachmentWorker.INPUT_DATA_USER_ACTION to userAction
))
.build()
workManager.enqueueUniqueWork(workName, ExistingWorkPolicy.KEEP, workRequest)
}
fun cancel(context: Context, id: String) {
val workManager = WorkManager.getInstance(context)
val workName = DOWNLOAD_WORK_NAME_PREFIX + id
Log.d(TAG, "Cancelling download for notification $id, work: $workName")
workManager.cancelUniqueWork(workName)
}
private fun enqueueIcon(context: Context, notificationId: String) {
val workManager = WorkManager.getInstance(context)
val workName = DOWNLOAD_WORK_ICON_NAME_PREFIX + notificationId
Log.d(TAG,"Enqueuing work to download icon for notification $notificationId, work: $workName")
val workRequest = OneTimeWorkRequest.Builder(DownloadIconWorker::class.java)
.setInputData(workDataOf(
DownloadAttachmentWorker.INPUT_DATA_ID to notificationId
))
.build()
workManager.enqueueUniqueWork(workName, ExistingWorkPolicy.KEEP, workRequest)
}
private fun enqueueAttachmentAndIcon(context: Context, notificationId: String, userAction: Boolean) {
val workManager = WorkManager.getInstance(context)
val workName = DOWNLOAD_WORK_BOTH_NAME_PREFIX + notificationId
val attachmentWorkRequest = OneTimeWorkRequest.Builder(DownloadAttachmentWorker::class.java)
.setInputData(workDataOf(
DownloadAttachmentWorker.INPUT_DATA_ID to notificationId,
DownloadAttachmentWorker.INPUT_DATA_USER_ACTION to userAction
))
.build()
val iconWorkRequest = OneTimeWorkRequest.Builder(DownloadIconWorker::class.java)
.setInputData(workDataOf(
DownloadAttachmentWorker.INPUT_DATA_ID to notificationId
))
.build()
Log.d(TAG,"Enqueuing work to download both attachment and icon for notification $notificationId, work: $workName")
workManager.beginUniqueWork(workName, ExistingWorkPolicy.KEEP, attachmentWorkRequest)
.then(iconWorkRequest)
.enqueue()
}
fun cancel(context: Context, id: String) {
val workManager = WorkManager.getInstance(context)
val workName = DOWNLOAD_WORK_ATTACHMENT_NAME_PREFIX + id
Log.d(TAG, "Cancelling attachment download for notification $id, work: $workName")
workManager.cancelUniqueWork(workName)
}
}
enum class DownloadType {
ATTACHMENT,
ICON,
BOTH
}

View file

@ -21,7 +21,7 @@ import okhttp3.Response
import java.io.File
import java.util.concurrent.TimeUnit
class DownloadAttachmentWorker(private val context: Context, params: WorkerParameters) : Worker(context, params) {
class DownloadWorker(private val context: Context, params: WorkerParameters) : Worker(context, params) {
private val client = OkHttpClient.Builder()
.callTimeout(15, TimeUnit.MINUTES) // Total timeout for entire request
.connectTimeout(15, TimeUnit.SECONDS)
@ -80,9 +80,9 @@ class DownloadAttachmentWorker(private val context: Context, params: WorkerParam
this.uri = uri // Required for cleanup in onStopped()
Log.d(TAG, "Starting download to content URI: $uri")
val contentLength = response.headers["Content-Length"]?.toLongOrNull()
var bytesCopied: Long = 0
val outFile = resolver.openOutputStream(uri) ?: throw Exception("Cannot open output stream")
val downloadLimit = getDownloadLimit(userAction)
outFile.use { fileOut ->
val fileIn = response.body!!.byteStream()
val buffer = ByteArray(BUFFER_SIZE)
@ -91,19 +91,19 @@ class DownloadAttachmentWorker(private val context: Context, params: WorkerParam
while (bytes >= 0) {
if (System.currentTimeMillis() - lastProgress > NOTIFICATION_UPDATE_INTERVAL_MILLIS) {
if (isStopped) { // Canceled by user
save(attachment.copy(progress = ATTACHMENT_PROGRESS_NONE))
save(attachment.copy(progress = PROGRESS_NONE))
return // File will be deleted in onStopped()
}
val progress = if (attachment.size != null && attachment.size!! > 0) {
(bytesCopied.toFloat()/attachment.size!!.toFloat()*100).toInt()
} else {
ATTACHMENT_PROGRESS_INDETERMINATE
PROGRESS_INDETERMINATE
}
save(attachment.copy(progress = progress))
lastProgress = System.currentTimeMillis()
}
if (downloadLimit != null && bytesCopied > downloadLimit) {
throw Exception("Attachment is longer than max download size.")
if (contentLength != null && bytesCopied > contentLength) {
throw Exception("Attachment is longer than response headers said.")
}
fileOut.write(buffer, 0, bytes)
bytesCopied += bytes
@ -114,7 +114,7 @@ class DownloadAttachmentWorker(private val context: Context, params: WorkerParam
save(attachment.copy(
size = bytesCopied,
contentUri = uri.toString(),
progress = ATTACHMENT_PROGRESS_DONE
progress = PROGRESS_DONE
))
}
} catch (e: Exception) {
@ -155,7 +155,7 @@ class DownloadAttachmentWorker(private val context: Context, params: WorkerParam
private fun failed(e: Exception) {
Log.w(TAG, "Attachment download failed", e)
save(attachment.copy(progress = ATTACHMENT_PROGRESS_FAILED))
save(attachment.copy(progress = PROGRESS_FAILED))
maybeDeleteFile()
}
@ -182,20 +182,12 @@ class DownloadAttachmentWorker(private val context: Context, params: WorkerParam
Repository.AUTO_DOWNLOAD_NEVER -> return true
Repository.AUTO_DOWNLOAD_ALWAYS -> return false
else -> {
val size = attachment.size ?: return false // Don't abort if size unknown
val size = attachment.size ?: return true // Abort if size unknown
return size > maxAutoDownloadSize
}
}
}
private fun getDownloadLimit(userAction: Boolean): Long? {
return if (userAction || repository.getAutoDownloadMaxSize() == Repository.AUTO_DOWNLOAD_ALWAYS) {
null
} else {
repository.getAutoDownloadMaxSize()
}
}
private fun createUri(notification: Notification): Uri {
val attachmentDir = File(context.cacheDir, ATTACHMENT_CACHE_DIR)
if (!attachmentDir.exists() && !attachmentDir.mkdirs()) {

View file

@ -13,8 +13,6 @@ data class Message(
val priority: Int?,
val tags: List<String>?,
val click: String?,
val icon: String?,
val actions: List<MessageAction>?,
val title: String?,
val message: String,
val encoding: String?,
@ -30,18 +28,4 @@ data class MessageAttachment(
val url: String,
)
@Keep
data class MessageAction(
val id: String,
val action: String,
val label: String, // "view", "broadcast" or "http"
val clear: Boolean?, // clear notification after successful execution
val url: String?, // used in "view" and "http" actions
val method: String?, // used in "http" action, default is POST (!)
val headers: Map<String,String>?, // used in "http" action
val body: String?, // used in "http" action
val intent: String?, // used in "broadcast" action
val extras: Map<String,String>?, // used in "broadcast" action
)
const val MESSAGE_ENCODING_BASE64 = "base64"

View file

@ -1,6 +1,7 @@
package io.heckel.ntfy.msg
import android.content.Context
import android.util.Base64
import io.heckel.ntfy.db.Notification
import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.db.Subscription
@ -19,7 +20,7 @@ class NotificationDispatcher(val context: Context, val repository: Repository) {
private val distributor = Distributor(context)
fun init() {
notifier.createDefaultNotificationChannels()
notifier.createNotificationChannels()
}
fun dispatch(subscription: Subscription, notification: Notification) {
@ -29,29 +30,24 @@ class NotificationDispatcher(val context: Context, val repository: Repository) {
val notify = shouldNotify(subscription, notification, muted)
val broadcast = shouldBroadcast(subscription)
val distribute = shouldDistribute(subscription)
val downloadAttachment = shouldDownloadAttachment(notification)
val downloadIcon = shouldDownloadIcon(notification)
val download = shouldDownload(notification)
if (notify) {
notifier.display(subscription, notification)
}
if (broadcast) {
broadcaster.sendMessage(subscription, notification, muted)
broadcaster.send(subscription, notification, muted)
}
if (distribute) {
safeLet(subscription.upAppId, subscription.upConnectorToken) { appId, connectorToken ->
distributor.sendMessage(appId, connectorToken, decodeBytesMessage(notification))
}
}
if (downloadAttachment && downloadIcon) {
DownloadManager.enqueue(context, notification.id, userAction = false, type = DownloadType.BOTH)
} else if (downloadAttachment) {
DownloadManager.enqueue(context, notification.id, userAction = false, type = DownloadType.ATTACHMENT)
} else if (downloadIcon) {
DownloadManager.enqueue(context, notification.id, userAction = false, type = DownloadType.ICON)
if (download) {
DownloadManager.enqueue(context, notification.id, userAction = false)
}
}
private fun shouldDownloadAttachment(notification: Notification): Boolean {
private fun shouldDownload(notification: Notification): Boolean {
if (notification.attachment == null) {
return false
}
@ -60,7 +56,8 @@ class NotificationDispatcher(val context: Context, val repository: Repository) {
Log.d(TAG, "Attachment already expired at ${attachment.expires}, not downloading")
return false
}
when (val maxAutoDownloadSize = repository.getAutoDownloadMaxSize()) {
val maxAutoDownloadSize = repository.getAutoDownloadMaxSize()
when (maxAutoDownloadSize) {
Repository.AUTO_DOWNLOAD_ALWAYS -> return true
Repository.AUTO_DOWNLOAD_NEVER -> return false
else -> {
@ -71,17 +68,13 @@ class NotificationDispatcher(val context: Context, val repository: Repository) {
}
}
}
private fun shouldDownloadIcon(notification: Notification): Boolean {
return notification.icon != null
}
private fun shouldNotify(subscription: Subscription, notification: Notification, muted: Boolean): Boolean {
if (subscription.upAppId != null) {
return false
}
val priority = if (notification.priority > 0) notification.priority else 3
val minPriority = if (subscription.minPriority > 0) subscription.minPriority else repository.getMinPriority()
if (priority < minPriority) {
if (priority < repository.getMinPriority()) {
return false
}
val detailsVisible = repository.detailViewSubscriptionId.get() == notification.subscriptionId

View file

@ -1,14 +1,11 @@
package io.heckel.ntfy.msg
import android.util.Base64
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import io.heckel.ntfy.db.Action
import io.heckel.ntfy.db.Attachment
import io.heckel.ntfy.db.Icon
import io.heckel.ntfy.db.Notification
import io.heckel.ntfy.util.joinTags
import io.heckel.ntfy.util.toPriority
import java.lang.reflect.Type
class NotificationParser {
private val gson = Gson()
@ -32,25 +29,6 @@ class NotificationParser {
url = message.attachment.url,
)
} else null
val actions = if (message.actions != null) {
message.actions.map { a ->
Action(
id = a.id,
action = a.action,
label = a.label,
clear = a.clear,
url = a.url,
method = a.method,
headers = a.headers,
body = a.body,
intent = a.intent,
extras = a.extras,
progress = null,
error = null
)
}
} else null
val icon: Icon? = if (message.icon != null && message.icon != "") Icon(url = message.icon) else null
val notification = Notification(
id = message.id,
subscriptionId = subscriptionId,
@ -61,8 +39,6 @@ class NotificationParser {
priority = toPriority(message.priority),
tags = joinTags(message.tags),
click = message.click ?: "",
icon = icon,
actions = actions,
attachment = attachment,
notificationId = notificationId,
deleted = false
@ -70,30 +46,5 @@ class NotificationParser {
return NotificationWithTopic(message.topic, notification)
}
/**
* Parse JSON array to Action list. The indirection via MessageAction is probably
* not necessary, but for "good form".
*/
fun parseActions(s: String?): List<Action>? {
val listType: Type = object : TypeToken<List<MessageAction>?>() {}.type
val messageActions: List<MessageAction>? = gson.fromJson(s, listType)
return messageActions?.map { a ->
Action(
id = a.id,
action = a.action,
label = a.label,
clear = a.clear,
url = a.url,
method = a.method,
headers = a.headers,
body = a.body,
intent = a.intent,
extras = a.extras,
progress = null,
error = null
)
}
}
data class NotificationWithTopic(val topic: String, val notification: Notification)
}

View file

@ -1,27 +1,24 @@
package io.heckel.ntfy.msg
import android.app.*
import android.content.ActivityNotFoundException
import android.content.BroadcastReceiver
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.TaskStackBuilder
import android.content.Context
import android.content.Intent
import android.media.AudioAttributes
import android.media.AudioManager
import android.graphics.BitmapFactory
import android.media.RingtoneManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.widget.Toast
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import io.heckel.ntfy.R
import io.heckel.ntfy.db.*
import io.heckel.ntfy.db.Notification
import io.heckel.ntfy.ui.Colors
import io.heckel.ntfy.ui.DetailActivity
import io.heckel.ntfy.ui.MainActivity
import io.heckel.ntfy.util.*
import java.util.*
class NotificationService(val context: Context) {
private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
@ -51,85 +48,34 @@ class NotificationService(val context: Context) {
}
}
fun cancel(notificationId: Int) {
if (notificationId != 0) {
Log.d(TAG, "Cancelling notification $notificationId")
notificationManager.cancel(notificationId)
}
}
fun createDefaultNotificationChannels() {
maybeCreateNotificationGroup(DEFAULT_GROUP, context.getString(R.string.channel_notifications_group_default_name))
ALL_PRIORITIES.forEach { priority -> maybeCreateNotificationChannel(DEFAULT_GROUP, priority) }
}
fun createSubscriptionNotificationChannels(subscription: Subscription) {
val groupId = subscriptionGroupId(subscription)
maybeCreateNotificationGroup(groupId, subscriptionGroupName(subscription))
ALL_PRIORITIES.forEach { priority -> maybeCreateNotificationChannel(groupId, priority) }
}
fun deleteSubscriptionNotificationChannels(subscription: Subscription) {
val groupId = subscriptionGroupId(subscription)
ALL_PRIORITIES.forEach { priority -> maybeDeleteNotificationChannel(groupId, priority) }
maybeDeleteNotificationGroup(groupId)
}
fun channelsSupported(): Boolean {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
}
private fun subscriptionGroupId(subscription: Subscription): String {
return SUBSCRIPTION_GROUP_PREFIX + subscription.id.toString()
}
private fun subscriptionGroupName(subscription: Subscription): String {
return subscription.displayName ?: subscriptionTopicShortUrl(subscription)
fun createNotificationChannels() {
(1..5).forEach { priority -> maybeCreateNotificationChannel(priority) }
}
private fun displayInternal(subscription: Subscription, notification: Notification, update: Boolean = false) {
val title = formatTitle(subscription, notification)
val groupId = if (subscription.dedicatedChannels) subscriptionGroupId(subscription) else DEFAULT_GROUP
val channelId = toChannelId(groupId, notification.priority)
val insistent = notification.priority == PRIORITY_MAX &&
(repository.getInsistentMaxPriorityEnabled() || subscription.insistent == Repository.INSISTENT_MAX_PRIORITY_ENABLED)
val channelId = toChannelId(notification.priority)
val builder = NotificationCompat.Builder(context, channelId)
.setSmallIcon(R.drawable.ic_notification)
.setColor(ContextCompat.getColor(context, Colors.notificationIcon(context)))
.setColor(ContextCompat.getColor(context, Colors.notificationIcon))
.setContentTitle(title)
.setOnlyAlertOnce(true) // Do not vibrate or play sound if already showing (updates!)
.setAutoCancel(true) // Cancel when notification is clicked
setStyleAndText(builder, subscription, notification) // Preview picture or big text style
setStyleAndText(builder, notification) // Preview picture or big text style
setClickAction(builder, subscription, notification)
maybeSetDeleteIntent(builder, insistent)
maybeSetSound(builder, insistent, update)
maybeSetSound(builder, update)
maybeSetProgress(builder, notification)
maybeAddOpenAction(builder, notification)
maybeAddBrowseAction(builder, notification)
maybeAddDownloadAction(builder, notification)
maybeAddCancelAction(builder, notification)
maybeAddUserActions(builder, notification)
maybeCreateNotificationGroup(groupId, subscriptionGroupName(subscription))
maybeCreateNotificationChannel(groupId, notification.priority)
maybePlayInsistentSound(groupId, insistent)
maybeCreateNotificationChannel(notification.priority)
notificationManager.notify(notification.notificationId, builder.build())
}
private fun maybeSetDeleteIntent(builder: NotificationCompat.Builder, insistent: Boolean) {
if (!insistent) {
return
}
val intent = Intent(context, DeleteBroadcastReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(context, Random().nextInt(), intent, PendingIntent.FLAG_IMMUTABLE)
builder.setDeleteIntent(pendingIntent)
}
private fun maybeSetSound(builder: NotificationCompat.Builder, insistent: Boolean, update: Boolean) {
// Note that the sound setting is ignored in Android => O (26) in favor of notification channels
val hasSound = !update && !insistent
if (hasSound) {
private fun maybeSetSound(builder: NotificationCompat.Builder, update: Boolean) {
if (!update) {
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
builder.setSound(defaultSoundUri)
} else {
@ -137,54 +83,52 @@ class NotificationService(val context: Context) {
}
}
private fun setStyleAndText(builder: NotificationCompat.Builder, subscription: Subscription, notification: Notification) {
private fun setStyleAndText(builder: NotificationCompat.Builder, notification: Notification) {
val contentUri = notification.attachment?.contentUri
val isSupportedImage = supportedImage(notification.attachment?.type)
val subscriptionIcon = if (subscription.icon != null) subscription.icon.readBitmapFromUriOrNull(context) else null
val notificationIcon = if (notification.icon != null) notification.icon.contentUri?.readBitmapFromUriOrNull(context) else null
val largeIcon = notificationIcon ?: subscriptionIcon
if (contentUri != null && isSupportedImage) {
try {
val attachmentBitmap = contentUri.readBitmapFromUri(context)
val resolver = context.applicationContext.contentResolver
val bitmapStream = resolver.openInputStream(Uri.parse(contentUri))
val bitmap = BitmapFactory.decodeStream(bitmapStream)
builder
.setContentText(maybeAppendActionErrors(formatMessage(notification), notification))
.setLargeIcon(attachmentBitmap)
.setContentText(formatMessage(notification))
.setLargeIcon(bitmap)
.setStyle(NotificationCompat.BigPictureStyle()
.bigPicture(attachmentBitmap)
.bigLargeIcon(largeIcon)) // May be null
.bigPicture(bitmap)
.bigLargeIcon(null))
} catch (_: Exception) {
val message = maybeAppendActionErrors(formatMessageMaybeWithAttachmentInfos(notification), notification)
val message = formatMessageMaybeWithAttachmentInfo(notification)
builder
.setContentText(message)
.setStyle(NotificationCompat.BigTextStyle().bigText(message))
}
} else {
val message = maybeAppendActionErrors(formatMessageMaybeWithAttachmentInfos(notification), notification)
val message = formatMessageMaybeWithAttachmentInfo(notification)
builder
.setContentText(message)
.setStyle(NotificationCompat.BigTextStyle().bigText(message))
.setLargeIcon(largeIcon) // May be null
}
}
private fun formatMessageMaybeWithAttachmentInfos(notification: Notification): String {
private fun formatMessageMaybeWithAttachmentInfo(notification: Notification): String {
val message = formatMessage(notification)
val attachment = notification.attachment ?: return message
val attachmentInfos = if (attachment.size != null) {
val infos = if (attachment.size != null) {
"${attachment.name}, ${formatBytes(attachment.size)}"
} else {
attachment.name
}
if (attachment.progress in 0..99) {
return context.getString(R.string.notification_popup_file_downloading, attachmentInfos, attachment.progress, message)
return context.getString(R.string.notification_popup_file_downloading, infos, attachment.progress, message)
}
if (attachment.progress == ATTACHMENT_PROGRESS_DONE) {
return context.getString(R.string.notification_popup_file_download_successful, message, attachmentInfos)
if (attachment.progress == PROGRESS_DONE) {
return context.getString(R.string.notification_popup_file_download_successful, message, infos)
}
if (attachment.progress == ATTACHMENT_PROGRESS_FAILED) {
return context.getString(R.string.notification_popup_file_download_failed, message, attachmentInfos)
if (attachment.progress == PROGRESS_FAILED) {
return context.getString(R.string.notification_popup_file_download_failed, message, infos)
}
return context.getString(R.string.notification_popup_file, message, attachmentInfos)
return context.getString(R.string.notification_popup_file, message, infos)
}
private fun setClickAction(builder: NotificationCompat.Builder, subscription: Subscription, notification: Notification) {
@ -193,7 +137,7 @@ class NotificationService(val context: Context) {
} else {
try {
val uri = Uri.parse(notification.click)
val viewIntent = PendingIntent.getActivity(context, Random().nextInt(), Intent(Intent.ACTION_VIEW, uri), PendingIntent.FLAG_IMMUTABLE)
val viewIntent = PendingIntent.getActivity(context, 0, Intent(Intent.ACTION_VIEW, uri), PendingIntent.FLAG_IMMUTABLE)
builder.setContentIntent(viewIntent)
} catch (e: Exception) {
builder.setContentIntent(detailActivityIntent(subscription))
@ -211,190 +155,93 @@ class NotificationService(val context: Context) {
}
private fun maybeAddOpenAction(builder: NotificationCompat.Builder, notification: Notification) {
if (!canOpenAttachment(notification.attachment)) {
return
}
if (notification.attachment?.contentUri != null) {
val contentUri = Uri.parse(notification.attachment.contentUri)
val intent = Intent(Intent.ACTION_VIEW, contentUri).apply {
setDataAndType(contentUri, notification.attachment.type ?: "application/octet-stream") // Required for Android <= P
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
val pendingIntent = PendingIntent.getActivity(context, Random().nextInt(), intent, PendingIntent.FLAG_IMMUTABLE)
val intent = Intent(Intent.ACTION_VIEW, contentUri)
intent.setDataAndType(contentUri, notification.attachment.type ?: "application/octet-stream") // Required for Android <= P
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
builder.addAction(NotificationCompat.Action.Builder(0, context.getString(R.string.notification_popup_action_open), pendingIntent).build())
}
}
private fun maybeAddBrowseAction(builder: NotificationCompat.Builder, notification: Notification) {
if (notification.attachment?.contentUri != null) {
val intent = Intent(android.app.DownloadManager.ACTION_VIEW_DOWNLOADS).apply {
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
val pendingIntent = PendingIntent.getActivity(context, Random().nextInt(), intent, PendingIntent.FLAG_IMMUTABLE)
val intent = Intent(android.app.DownloadManager.ACTION_VIEW_DOWNLOADS)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
builder.addAction(NotificationCompat.Action.Builder(0, context.getString(R.string.notification_popup_action_browse), pendingIntent).build())
}
}
private fun maybeAddDownloadAction(builder: NotificationCompat.Builder, notification: Notification) {
if (notification.attachment?.contentUri == null && listOf(ATTACHMENT_PROGRESS_NONE, ATTACHMENT_PROGRESS_FAILED).contains(notification.attachment?.progress)) {
val intent = Intent(context, UserActionBroadcastReceiver::class.java).apply {
putExtra(BROADCAST_EXTRA_TYPE, BROADCAST_TYPE_DOWNLOAD_START)
putExtra(BROADCAST_EXTRA_NOTIFICATION_ID, notification.id)
}
val pendingIntent = PendingIntent.getBroadcast(context, Random().nextInt(), intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
if (notification.attachment?.contentUri == null && listOf(PROGRESS_NONE, PROGRESS_FAILED).contains(notification.attachment?.progress)) {
val intent = Intent(context, DownloadBroadcastReceiver::class.java)
intent.putExtra("action", DOWNLOAD_ACTION_START)
intent.putExtra("id", notification.id)
val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
builder.addAction(NotificationCompat.Action.Builder(0, context.getString(R.string.notification_popup_action_download), pendingIntent).build())
}
}
private fun maybeAddCancelAction(builder: NotificationCompat.Builder, notification: Notification) {
if (notification.attachment?.contentUri == null && notification.attachment?.progress in 0..99) {
val intent = Intent(context, UserActionBroadcastReceiver::class.java).apply {
putExtra(BROADCAST_EXTRA_TYPE, BROADCAST_TYPE_DOWNLOAD_CANCEL)
putExtra(BROADCAST_EXTRA_NOTIFICATION_ID, notification.id)
}
val pendingIntent = PendingIntent.getBroadcast(context, Random().nextInt(), intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
val intent = Intent(context, DownloadBroadcastReceiver::class.java)
intent.putExtra("action", DOWNLOAD_ACTION_CANCEL)
intent.putExtra("id", notification.id)
val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
builder.addAction(NotificationCompat.Action.Builder(0, context.getString(R.string.notification_popup_action_cancel), pendingIntent).build())
}
}
private fun maybeAddUserActions(builder: NotificationCompat.Builder, notification: Notification) {
notification.actions?.forEach { action ->
val actionType = action.action.lowercase(Locale.getDefault())
if (actionType == ACTION_VIEW) {
// Hack: Action "view" with "clear=true" is a special case, because it's apparently impossible to start a
// URL activity from PendingIntent.getActivity() and also close the notification. To clear it, we
// launch our own Activity (ViewActionWithClearActivity) which then calls the actual activity
if (action.clear == true) {
addViewUserActionWithClear(builder, notification, action)
} else {
addViewUserActionWithoutClear(builder, action)
}
} else {
addHttpOrBroadcastUserAction(builder, notification, action)
}
}
}
/**
* Open the URL and do NOT cancel the notification (clear=false). This uses a normal Intent with the given URL.
* The other case is much more interesting.
*/
private fun addViewUserActionWithoutClear(builder: NotificationCompat.Builder, action: Action) {
try {
val url = action.url ?: return
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply {
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
}
val pendingIntent = PendingIntent.getActivity(context, Random().nextInt(), intent, PendingIntent.FLAG_IMMUTABLE)
builder.addAction(NotificationCompat.Action.Builder(0, action.label, pendingIntent).build())
} catch (e: Exception) {
Log.w(TAG, "Unable to add open user action", e)
}
}
/**
* HACK: Open the URL and CANCEL the notification (clear=true). This is a SPECIAL case with a horrible workaround.
* We call our own activity ViewActionWithClearActivity and open the URL from there.
*/
private fun addViewUserActionWithClear(builder: NotificationCompat.Builder, notification: Notification, action: Action) {
try {
val url = action.url ?: return
val intent = Intent(context, ViewActionWithClearActivity::class.java).apply {
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
putExtra(VIEW_ACTION_EXTRA_URL, url)
putExtra(VIEW_ACTION_EXTRA_NOTIFICATION_ID, notification.notificationId)
}
val pendingIntent = PendingIntent.getActivity(context, Random().nextInt(), intent, PendingIntent.FLAG_IMMUTABLE)
builder.addAction(NotificationCompat.Action.Builder(0, action.label, pendingIntent).build())
} catch (e: Exception) {
Log.w(TAG, "Unable to add open user action", e)
}
}
private fun addHttpOrBroadcastUserAction(builder: NotificationCompat.Builder, notification: Notification, action: Action) {
val intent = Intent(context, UserActionBroadcastReceiver::class.java).apply {
putExtra(BROADCAST_EXTRA_TYPE, BROADCAST_TYPE_USER_ACTION)
putExtra(BROADCAST_EXTRA_NOTIFICATION_ID, notification.id)
putExtra(BROADCAST_EXTRA_ACTION_ID, action.id)
}
val pendingIntent = PendingIntent.getBroadcast(context, Random().nextInt(), intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
val label = formatActionLabel(action)
builder.addAction(NotificationCompat.Action.Builder(0, label, pendingIntent).build())
}
/**
* Receives the broadcast from
* - the "http" and "broadcast" action button (the "view" action is handled differently)
* - the "download"/"cancel" action button
*
* Then queues a Worker via WorkManager to execute the action in the background
*/
class UserActionBroadcastReceiver : BroadcastReceiver() {
class DownloadBroadcastReceiver : android.content.BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val type = intent.getStringExtra(BROADCAST_EXTRA_TYPE) ?: return
val notificationId = intent.getStringExtra(BROADCAST_EXTRA_NOTIFICATION_ID) ?: return
when (type) {
BROADCAST_TYPE_DOWNLOAD_START -> DownloadManager.enqueue(context, notificationId, userAction = true, DownloadType.ATTACHMENT)
BROADCAST_TYPE_DOWNLOAD_CANCEL -> DownloadManager.cancel(context, notificationId)
BROADCAST_TYPE_USER_ACTION -> {
val actionId = intent.getStringExtra(BROADCAST_EXTRA_ACTION_ID) ?: return
UserActionManager.enqueue(context, notificationId, actionId)
}
val id = intent.getStringExtra("id") ?: return
val action = intent.getStringExtra("action") ?: return
when (action) {
DOWNLOAD_ACTION_START -> DownloadManager.enqueue(context, id, userAction = true)
DOWNLOAD_ACTION_CANCEL -> DownloadManager.cancel(context, id)
}
}
}
/**
* Receives a broadcast when a notification is swiped away. This is currently
* only called for notifications with an insistent sound.
*/
class DeleteBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.d(TAG, "Media player: Stopping insistent ring")
val mediaPlayer = Repository.getInstance(context).mediaPlayer
mediaPlayer.stop()
}
}
private fun detailActivityIntent(subscription: Subscription): PendingIntent? {
val intent = Intent(context, DetailActivity::class.java).apply {
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)
}
val intent = Intent(context, DetailActivity::class.java)
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_INSTANT, subscription.instant)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_MUTED_UNTIL, subscription.mutedUntil)
return TaskStackBuilder.create(context).run {
addNextIntentWithParentStack(intent) // Add the intent, which inflates the back stack
getPendingIntent(Random().nextInt(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) // Get the PendingIntent containing the entire back stack
getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) // Get the PendingIntent containing the entire back stack
}
}
private fun maybeCreateNotificationChannel(group: String, priority: Int) {
if (channelsSupported()) {
private fun maybeCreateNotificationChannel(priority: Int) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// Note: To change a notification channel, you must delete the old one and create a new one!
val channelId = toChannelId(group, priority)
val dndOverridePriority = repository.getDnsOverridePriority()
val pause = 300L
val channel = when (priority) {
PRIORITY_MIN -> NotificationChannel(channelId, context.getString(R.string.channel_notifications_min_name), NotificationManager.IMPORTANCE_MIN)
PRIORITY_LOW -> NotificationChannel(channelId, context.getString(R.string.channel_notifications_low_name), NotificationManager.IMPORTANCE_LOW)
PRIORITY_HIGH -> {
val channel = NotificationChannel(channelId, context.getString(R.string.channel_notifications_high_name), NotificationManager.IMPORTANCE_HIGH)
1 -> NotificationChannel(CHANNEL_ID_MIN, context.getString(R.string.channel_notifications_min_name), NotificationManager.IMPORTANCE_MIN)
2 -> NotificationChannel(CHANNEL_ID_LOW, context.getString(R.string.channel_notifications_low_name), NotificationManager.IMPORTANCE_LOW)
4 -> {
val channel = NotificationChannel(CHANNEL_ID_HIGH, context.getString(R.string.channel_notifications_high_name), NotificationManager.IMPORTANCE_HIGH)
channel.enableVibration(true)
channel.setBypassDnd(dndOverridePriority >= 4)
channel.vibrationPattern = longArrayOf(
pause, 100, pause, 100, pause, 100,
pause, 2000
)
channel
}
PRIORITY_MAX -> {
val channel = NotificationChannel(channelId, context.getString(R.string.channel_notifications_max_name), NotificationManager.IMPORTANCE_HIGH) // IMPORTANCE_MAX does not exist
5 -> {
val channel = NotificationChannel(CHANNEL_ID_MAX, context.getString(R.string.channel_notifications_max_name), NotificationManager.IMPORTANCE_HIGH) // IMPORTANCE_MAX does not exist
channel.enableLights(true)
channel.enableVibration(true)
channel.setBypassDnd(true)
channel.setBypassDnd(dndOverridePriority >= 4)
channel.vibrationPattern = longArrayOf(
pause, 100, pause, 100, pause, 100,
pause, 2000,
@ -405,139 +252,31 @@ class NotificationService(val context: Context) {
)
channel
}
else -> NotificationChannel(channelId, context.getString(R.string.channel_notifications_default_name), NotificationManager.IMPORTANCE_DEFAULT)
else -> NotificationChannel(CHANNEL_ID_DEFAULT, context.getString(R.string.channel_notifications_default_name), NotificationManager.IMPORTANCE_DEFAULT)
}
channel.group = group
notificationManager.createNotificationChannel(channel)
}
}
private fun maybeDeleteNotificationChannel(group: String, priority: Int) {
if (channelsSupported()) {
notificationManager.deleteNotificationChannel(toChannelId(group, priority))
}
}
private fun maybeCreateNotificationGroup(id: String, name: String) {
if (channelsSupported()) {
notificationManager.createNotificationChannelGroup(NotificationChannelGroup(id, name))
}
}
private fun maybeDeleteNotificationGroup(id: String) {
if (channelsSupported()) {
notificationManager.deleteNotificationChannelGroup(id)
}
}
private fun toChannelId(groupId: String, priority: Int): String {
private fun toChannelId(priority: Int): String {
return when (priority) {
PRIORITY_MIN -> groupId + GROUP_SUFFIX_PRIORITY_MIN
PRIORITY_LOW -> groupId + GROUP_SUFFIX_PRIORITY_LOW
PRIORITY_HIGH -> groupId + GROUP_SUFFIX_PRIORITY_HIGH
PRIORITY_MAX -> groupId + GROUP_SUFFIX_PRIORITY_MAX
else -> groupId + GROUP_SUFFIX_PRIORITY_DEFAULT
}
}
private fun maybePlayInsistentSound(groupId: String, insistent: Boolean) {
if (!insistent) {
return
}
try {
val mediaPlayer = repository.mediaPlayer
val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) {
Log.d(TAG, "Media player: Playing insistent alarm on alarm channel")
mediaPlayer.reset()
mediaPlayer.setDataSource(context, getInsistentSound(groupId))
mediaPlayer.setAudioAttributes(AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM).build())
mediaPlayer.isLooping = true
mediaPlayer.prepare()
mediaPlayer.start()
} else {
Log.d(TAG, "Media player: Alarm volume is 0; not playing insistent alarm")
}
} catch (e: Exception) {
Log.w(TAG, "Media player: Failed to play insistent alarm", e)
}
}
private fun getInsistentSound(groupId: String): Uri {
return if (channelsSupported()) {
val channelId = toChannelId(groupId, PRIORITY_MAX)
val channel = notificationManager.getNotificationChannel(channelId)
channel.sound
} else {
RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
}
}
/**
* Activity used to launch a URL.
* .
* Horrible hack: Action "view" with "clear=true" is a special case, because it's apparently impossible to start a
* URL activity from PendingIntent.getActivity() and also close the notification. To clear it, we
* launch this activity which then calls the actual activity.
*/
class ViewActionWithClearActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d(TAG, "Created $this")
val url = intent.getStringExtra(VIEW_ACTION_EXTRA_URL)
val notificationId = intent.getIntExtra(VIEW_ACTION_EXTRA_NOTIFICATION_ID, 0)
if (url == null) {
finish()
return
}
// Immediately start the actual activity
try {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply {
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
startActivity(intent)
} catch (e: Exception) {
Log.w(TAG, "Unable to start activity from URL $url", e)
val message = if (e is ActivityNotFoundException) url else e.message
Toast
.makeText(this, getString(R.string.detail_item_cannot_open_url, message), Toast.LENGTH_LONG)
.show()
}
// Cancel notification
val notifier = NotificationService(this)
notifier.cancel(notificationId)
// Close this activity
finish()
1 -> CHANNEL_ID_MIN
2 -> CHANNEL_ID_LOW
4 -> CHANNEL_ID_HIGH
5 -> CHANNEL_ID_MAX
else -> CHANNEL_ID_DEFAULT
}
}
companion object {
const val ACTION_VIEW = "view"
const val ACTION_HTTP = "http"
const val ACTION_BROADCAST = "broadcast"
const val BROADCAST_EXTRA_TYPE = "type"
const val BROADCAST_EXTRA_NOTIFICATION_ID = "notificationId"
const val BROADCAST_EXTRA_ACTION_ID = "actionId"
const val BROADCAST_TYPE_DOWNLOAD_START = "io.heckel.ntfy.DOWNLOAD_ACTION_START"
const val BROADCAST_TYPE_DOWNLOAD_CANCEL = "io.heckel.ntfy.DOWNLOAD_ACTION_CANCEL"
const val BROADCAST_TYPE_USER_ACTION = "io.heckel.ntfy.USER_ACTION_RUN"
private const val TAG = "NtfyNotifService"
private const val DOWNLOAD_ACTION_START = "io.heckel.ntfy.DOWNLOAD_ACTION_START"
private const val DOWNLOAD_ACTION_CANCEL = "io.heckel.ntfy.DOWNLOAD_ACTION_CANCEL"
private const val DEFAULT_GROUP = "ntfy"
private const val SUBSCRIPTION_GROUP_PREFIX = "ntfy-subscription-"
private const val GROUP_SUFFIX_PRIORITY_MIN = "-min"
private const val GROUP_SUFFIX_PRIORITY_LOW = "-low"
private const val GROUP_SUFFIX_PRIORITY_DEFAULT = ""
private const val GROUP_SUFFIX_PRIORITY_HIGH = "-high"
private const val GROUP_SUFFIX_PRIORITY_MAX = "-max"
private const val VIEW_ACTION_EXTRA_URL = "url"
private const val VIEW_ACTION_EXTRA_NOTIFICATION_ID = "notificationId"
private const val CHANNEL_ID_MIN = "ntfy-min"
private const val CHANNEL_ID_LOW = "ntfy-low"
private const val CHANNEL_ID_DEFAULT = "ntfy"
private const val CHANNEL_ID_HIGH = "ntfy-high"
private const val CHANNEL_ID_MAX = "ntfy-max"
}
}

View file

@ -1,32 +0,0 @@
package io.heckel.ntfy.msg
import android.content.Context
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import androidx.work.workDataOf
import io.heckel.ntfy.util.Log
/**
* Trigger user actions clicked from notification popups.
*
* 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.
*/
object UserActionManager {
private const val TAG = "NtfyUserActionEx"
private const val WORK_NAME_PREFIX = "io.heckel.ntfy.USER_ACTION_"
fun enqueue(context: Context, notificationId: String, actionId: String) {
val workManager = WorkManager.getInstance(context)
val workName = WORK_NAME_PREFIX + notificationId + "_" + actionId
Log.d(TAG,"Enqueuing work to execute user action for notification $notificationId, action $actionId, work: $workName")
val workRequest = OneTimeWorkRequest.Builder(UserActionWorker::class.java)
.setInputData(workDataOf(
UserActionWorker.INPUT_DATA_NOTIFICATION_ID to notificationId,
UserActionWorker.INPUT_DATA_ACTION_ID to actionId,
))
.build()
workManager.enqueueUniqueWork(workName, ExistingWorkPolicy.KEEP, workRequest)
}
}

View file

@ -1,115 +0,0 @@
package io.heckel.ntfy.msg
import android.content.Context
import androidx.work.Worker
import androidx.work.WorkerParameters
import io.heckel.ntfy.R
import io.heckel.ntfy.app.Application
import io.heckel.ntfy.db.*
import io.heckel.ntfy.msg.NotificationService.Companion.ACTION_BROADCAST
import io.heckel.ntfy.msg.NotificationService.Companion.ACTION_HTTP
import io.heckel.ntfy.util.Log
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import java.util.*
import java.util.concurrent.TimeUnit
class UserActionWorker(private val context: Context, params: WorkerParameters) : Worker(context, params) {
private val client = OkHttpClient.Builder()
.callTimeout(60, TimeUnit.SECONDS) // Total timeout for entire request
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.build()
private val notifier = NotificationService(context)
private val broadcaster = BroadcastService(context)
private lateinit var repository: Repository
private lateinit var subscription: Subscription
private lateinit var notification: Notification
private lateinit var action: Action
override fun doWork(): Result {
if (context.applicationContext !is Application) return Result.failure()
val notificationId = inputData.getString(INPUT_DATA_NOTIFICATION_ID) ?: return Result.failure()
val actionId = inputData.getString(INPUT_DATA_ACTION_ID) ?: return Result.failure()
val app = context.applicationContext as Application
repository = app.repository
notification = repository.getNotification(notificationId) ?: return Result.failure()
subscription = repository.getSubscription(notification.subscriptionId) ?: return Result.failure()
action = notification.actions?.first { it.id == actionId } ?: return Result.failure()
Log.d(TAG, "Executing action $action for notification $notification")
try {
when (action.action) {
// ACTION_VIEW is not handled here. It's handled in the NotificationService and DetailAdapter.
ACTION_BROADCAST -> performBroadcastAction(action)
ACTION_HTTP -> performHttpAction(action)
}
} catch (e: Exception) {
Log.w(TAG, "Error executing action: ${e.message}", e)
save(action.copy(
progress = ACTION_PROGRESS_FAILED,
error = context.getString(R.string.notification_popup_user_action_failed, action.label, e.message)
))
}
return Result.success()
}
private fun performBroadcastAction(action: Action) {
broadcaster.sendUserAction(action)
if (action.clear == true) {
notifier.cancel(notification)
}
}
private fun performHttpAction(action: Action) {
save(action.copy(progress = ACTION_PROGRESS_ONGOING, error = null))
val url = action.url ?: return
val method = action.method ?: DEFAULT_HTTP_ACTION_METHOD
val defaultBody = if (listOf("GET", "HEAD").contains(method)) null else ""
val body = action.body ?: defaultBody
val builder = Request.Builder()
.url(url)
.method(method, body?.toRequestBody())
.addHeader("User-Agent", ApiService.USER_AGENT)
action.headers?.forEach { (key, value) ->
builder.addHeader(key, value)
}
val request = builder.build()
Log.d(TAG, "Executing HTTP request: ${method.uppercase(Locale.getDefault())} ${action.url}")
client.newCall(request).execute().use { response ->
if (response.isSuccessful) {
save(action.copy(progress = ACTION_PROGRESS_SUCCESS, error = null))
return
}
throw Exception("HTTP ${response.code}")
}
}
private fun save(newAction: Action) {
Log.d(TAG, "Updating action: $newAction")
val clear = newAction.progress == ACTION_PROGRESS_SUCCESS && action.clear == true
val newActions = notification.actions?.map { a -> if (a.id == newAction.id) newAction else a }
val newNotification = notification.copy(actions = newActions)
action = newAction
notification = newNotification
repository.updateNotification(notification)
if (clear) {
notifier.cancel(notification)
} else {
notifier.update(subscription, notification)
}
}
companion object {
const val INPUT_DATA_NOTIFICATION_ID = "notificationId"
const val INPUT_DATA_ACTION_ID = "actionId"
private const val DEFAULT_HTTP_ACTION_METHOD = "POST" // Cannot be changed without changing the contract
private const val TAG = "NtfyUserActWrk"
}
}

View file

@ -3,11 +3,10 @@ package io.heckel.ntfy.service
interface Connection {
fun start()
fun close()
fun since(): String?
fun since(): Long
}
data class ConnectionId(
val baseUrl: String,
val topicsToSubscriptionIds: Map<String, Long>,
val topicIsUnifiedPush: Map<String, Boolean>
val topicsToSubscriptionIds: Map<String, Long>
)

View file

@ -14,20 +14,18 @@ class JsonConnection(
private val repository: Repository,
private val api: ApiService,
private val user: User?,
private val sinceId: String?,
private val sinceTime: Long,
private val stateChangeListener: (Collection<Long>, ConnectionState) -> Unit,
private val notificationListener: (Subscription, Notification) -> Unit,
private val serviceActive: () -> Boolean
) : Connection {
private val baseUrl = connectionId.baseUrl
private val topicsToSubscriptionIds = connectionId.topicsToSubscriptionIds
private val topicIsUnifiedPush = connectionId.topicIsUnifiedPush
private val subscriptionIds = topicsToSubscriptionIds.values
private val topicsStr = topicsToSubscriptionIds.keys.joinToString(separator = ",")
private val unifiedPushTopicsStr = topicIsUnifiedPush.filter { entry -> entry.value }.keys.joinToString(separator = ",")
private val url = topicUrl(baseUrl, topicsStr)
private var since: String? = sinceId
private var since: Long = sinceTime
private lateinit var call: Call
private lateinit var job: Job
@ -41,7 +39,7 @@ class JsonConnection(
Log.d(TAG, "[$url] (Re-)starting connection for subscriptions: $topicsToSubscriptionIds")
val startTime = System.currentTimeMillis()
val notify = notify@ { topic: String, notification: Notification ->
since = notification.id
since = notification.timestamp
val subscriptionId = topicsToSubscriptionIds[topic] ?: return@notify
val subscription = repository.getSubscription(subscriptionId) ?: return@notify
val notificationWithSubscriptionId = notification.copy(subscriptionId = subscription.id)
@ -58,7 +56,7 @@ class JsonConnection(
// Call /json subscribe endpoint and loop until the call fails, is canceled,
// or the job or service are cancelled/stopped
try {
call = api.subscribe(baseUrl, topicsStr, unifiedPushTopicsStr, since, user, notify, fail)
call = api.subscribe(baseUrl, topicsStr, since, user, notify, fail)
while (!failed.get() && !call.isCanceled() && isActive && serviceActive()) {
stateChangeListener(subscriptionIds, ConnectionState.CONNECTED)
Log.d(TAG,"[$url] Connection is active (failed=$failed, callCanceled=${call.isCanceled()}, jobActive=$isActive, serviceStarted=${serviceActive()}")
@ -83,7 +81,7 @@ class JsonConnection(
}
}
override fun since(): String? {
override fun since(): Long {
return since
}

View file

@ -10,18 +10,17 @@ import android.os.PowerManager
import android.os.SystemClock
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import androidx.preference.PreferenceManager
import io.heckel.ntfy.BuildConfig
import io.heckel.ntfy.R
import io.heckel.ntfy.app.Application
import io.heckel.ntfy.db.ConnectionState
import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.db.Subscription
import io.heckel.ntfy.util.Log
import io.heckel.ntfy.msg.ApiService
import io.heckel.ntfy.msg.NotificationDispatcher
import io.heckel.ntfy.ui.Colors
import io.heckel.ntfy.ui.MainActivity
import io.heckel.ntfy.util.Log
import io.heckel.ntfy.util.topicUrl
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@ -89,16 +88,23 @@ class SubscriberService : Service() {
Log.init(this) // Init logs in all entry points
Log.d(TAG, "Subscriber service has been created")
val title = getString(R.string.channel_subscriber_notification_title)
val text = if (BuildConfig.FIREBASE_AVAILABLE) {
getString(R.string.channel_subscriber_notification_instant_text)
} else {
getString(R.string.channel_subscriber_notification_noinstant_text)
}
notificationManager = createNotificationChannel()
serviceNotification = createNotification(title, text)
startForeground(NOTIFICATION_SERVICE_ID, serviceNotification)
}
override fun onDestroy() {
Log.d(TAG, "Subscriber service has been destroyed")
stopService()
val preferenceKey = getString(R.string.eos_preference_key_is_enabled)
if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean(preferenceKey, false)) {
sendBroadcast(Intent(this, AutoRestartReceiver::class.java))
}
sendBroadcast(Intent(this, AutoRestartReceiver::class.java)) // Restart it if necessary!
super.onDestroy()
}
@ -132,6 +138,7 @@ class SubscriberService : Service() {
}
}
wakeLock = null
stopForeground(true)
stopSelf()
} catch (e: Exception) {
Log.d(TAG, "Service stopped without being started: ${e.message}")
@ -165,14 +172,20 @@ class SubscriberService : Service() {
.filter { s -> s.instant }
val activeConnectionIds = connections.keys().toList().toSet()
val desiredConnectionIds = instantSubscriptions // Set<ConnectionId>
.groupBy { s -> ConnectionId(s.baseUrl, emptyMap(), emptyMap()) }
.map { entry -> entry.key.copy(topicsToSubscriptionIds = entry.value.associate { s -> s.topic to s.id }, topicIsUnifiedPush = entry.value.associate { s -> s.topic to (s.upConnectorToken != null) }) }
.groupBy { s -> ConnectionId(s.baseUrl, emptyMap()) }
.map { entry -> entry.key.copy(topicsToSubscriptionIds = entry.value.associate { s -> s.topic to s.id }) }
.toSet()
val newConnectionIds = desiredConnectionIds.subtract(activeConnectionIds)
val obsoleteConnectionIds = activeConnectionIds.subtract(desiredConnectionIds)
val match = activeConnectionIds == desiredConnectionIds
val sinceByBaseUrl = connections
.map { e -> e.key.baseUrl to e.value.since() } // Use since=<id>, avoid retrieving old messages (see comment below)
val newSinceByBaseUrl = connections
.map { e ->
// Get last message timestamp to determine new ?since= param; set to $last+1 if it
// is defined to avoid retrieving old messages. See comment below too.
val lastMessage = e.value.since()
val newSince = if (lastMessage > 0) lastMessage+1 else 0
e.key.baseUrl to newSince
}
.toMap()
Log.d(TAG, "Refreshing subscriptions")
@ -192,8 +205,8 @@ class SubscriberService : Service() {
// IMPORTANT: Do NOT request old messages for new connections; we call poll() in MainActivity to
// 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 since = newSinceByBaseUrl[connectionId.baseUrl] ?: (System.currentTimeMillis() / 1000)
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
@ -220,8 +233,6 @@ class SubscriberService : Service() {
2 -> getString(R.string.channel_subscriber_notification_instant_text_two)
3 -> getString(R.string.channel_subscriber_notification_instant_text_three)
4 -> getString(R.string.channel_subscriber_notification_instant_text_four)
5 -> getString(R.string.channel_subscriber_notification_instant_text_five)
6 -> getString(R.string.channel_subscriber_notification_instant_text_six)
else -> getString(R.string.channel_subscriber_notification_instant_text_more, instantSubscriptions.size)
}
} else {
@ -230,8 +241,6 @@ class SubscriberService : Service() {
2 -> getString(R.string.channel_subscriber_notification_noinstant_text_two)
3 -> getString(R.string.channel_subscriber_notification_noinstant_text_three)
4 -> getString(R.string.channel_subscriber_notification_noinstant_text_four)
5 -> getString(R.string.channel_subscriber_notification_noinstant_text_five)
6 -> getString(R.string.channel_subscriber_notification_noinstant_text_six)
else -> getString(R.string.channel_subscriber_notification_noinstant_text_more, instantSubscriptions.size)
}
}
@ -284,14 +293,12 @@ class SubscriberService : Service() {
}
return NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification_instant)
.setColor(ContextCompat.getColor(this, Colors.notificationIcon(this)))
.setColor(ContextCompat.getColor(this, Colors.notificationIcon))
.setContentTitle(title)
.setContentText(text)
.setContentIntent(pendingIntent)
.setSound(null)
.setShowWhen(false) // Don't show date/time
.setOngoing(true) // Starting SDK 33 / Android 13, foreground notifications can be swiped away
.setGroup(NOTIFICATION_GROUP_ID) // Do not group with other notifications
.build()
}
@ -303,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 */
@ -346,7 +353,6 @@ class SubscriberService : Service() {
private const val WAKE_LOCK_TAG = "SubscriberService:lock"
private const val NOTIFICATION_CHANNEL_ID = "ntfy-subscriber"
private const val NOTIFICATION_GROUP_ID = "io.heckel.ntfy.NOTIFICATION_GROUP_SERVICE"
private const val NOTIFICATION_SERVICE_ID = 2586
private const val NOTIFICATION_RECEIVED_WAKELOCK_TIMEOUT_MILLIS = 10*60*1000L /*10 minutes*/
private const val SHARED_PREFS_ID = "SubscriberService"

View file

@ -2,11 +2,10 @@ package io.heckel.ntfy.service
import android.content.Context
import android.content.Intent
import androidx.preference.PreferenceManager
import androidx.core.content.ContextCompat
import androidx.work.*
import io.heckel.ntfy.app.Application
import io.heckel.ntfy.util.Log
import io.heckel.ntfy.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@ -44,17 +43,11 @@ class SubscriberServiceManager(private val context: Context) {
Log.d(TAG, "ServiceStartWorker: Failed, no application found (work ID: ${id})")
return Result.failure()
}
withContext(Dispatchers.IO) {
val app = context.applicationContext as Application
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(app)
val preferenceKey = context.getString(R.string.eos_preference_key_is_enabled)
val action = if (sharedPreferences.getBoolean(preferenceKey, false)) {
SubscriberService.Action.START
} else {
SubscriberService.Action.STOP
}
val subscriptionIdsWithInstantStatus = app.repository.getSubscriptionIdsWithInstantStatus()
val instantSubscriptions = subscriptionIdsWithInstantStatus.toList().filter { (_, instant) -> instant }.size
val action = if (instantSubscriptions > 0) SubscriberService.Action.START else SubscriberService.Action.STOP
val serviceState = SubscriberService.readServiceState(context)
if (serviceState == SubscriberService.ServiceState.STOPPED && action == SubscriberService.Action.STOP) {
return@withContext Result.success()
@ -62,7 +55,7 @@ class SubscriberServiceManager(private val context: Context) {
Log.d(TAG, "ServiceStartWorker: Starting foreground service with action $action (work ID: ${id})")
Intent(context, SubscriberService::class.java).also {
it.action = action.name
context.startService(it)
ContextCompat.startForegroundService(context, it)
}
}
return Result.success()

View file

@ -5,19 +5,15 @@ import android.os.Build
import android.os.Handler
import android.os.Looper
import io.heckel.ntfy.db.*
import io.heckel.ntfy.util.Log
import io.heckel.ntfy.msg.ApiService.Companion.requestBuilder
import io.heckel.ntfy.msg.NotificationParser
import io.heckel.ntfy.util.Log
import io.heckel.ntfy.util.topicShortUrl
import io.heckel.ntfy.util.topicUrlWs
import okhttp3.OkHttpClient
import okhttp3.Response
import okhttp3.WebSocket
import okhttp3.WebSocketListener
import okhttp3.*
import java.util.*
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicLong
import java.util.concurrent.atomic.AtomicReference
import kotlin.random.Random
/**
@ -34,7 +30,7 @@ class WsConnection(
private val connectionId: ConnectionId,
private val repository: Repository,
private val user: User?,
private val sinceId: String?,
private val sinceTime: Long,
private val stateChangeListener: (Collection<Long>, ConnectionState) -> Unit,
private val notificationListener: (Subscription, Notification) -> Unit,
private val alarmManager: AlarmManager
@ -53,13 +49,11 @@ class WsConnection(
private val globalId = GLOBAL_ID.incrementAndGet()
private val listenerId = AtomicLong(0)
private val since = AtomicReference<String?>(sinceId)
private val since = AtomicLong(sinceTime)
private val baseUrl = connectionId.baseUrl
private val topicsToSubscriptionIds = connectionId.topicsToSubscriptionIds
private val topicIsUnifiedPush = connectionId.topicIsUnifiedPush
private val subscriptionIds = topicsToSubscriptionIds.values
private val topicsStr = topicsToSubscriptionIds.keys.joinToString(separator = ",")
private val unifiedPushTopicsStr = topicIsUnifiedPush.filter { entry -> entry.value }.keys.joinToString(separator = ",")
private val shortUrl = topicShortUrl(baseUrl, topicsStr)
init {
@ -77,10 +71,9 @@ class WsConnection(
}
state = State.Connecting
val nextListenerId = listenerId.incrementAndGet()
val sinceId = since.get()
val sinceVal = sinceId ?: "all"
val sinceVal = if (since.get() == 0L) "all" else since.get().toString()
val urlWithSince = topicUrlWs(baseUrl, topicsStr, sinceVal)
val request = requestBuilder(urlWithSince, user, unifiedPushTopicsStr).build()
val request = requestBuilder(urlWithSince, user).build()
Log.d(TAG, "$shortUrl (gid=$globalId): Opening $urlWithSince with listener ID $nextListenerId ...")
webSocket = client.newWebSocket(request, Listener(nextListenerId))
}
@ -99,7 +92,7 @@ class WsConnection(
}
@Synchronized
override fun since(): String? {
override fun since(): Long {
return since.get()
}
@ -148,7 +141,7 @@ class WsConnection(
val subscription = repository.getSubscription(subscriptionId) ?: return@synchronize
val notificationWithSubscriptionId = notification.copy(subscriptionId = subscription.id)
notificationListener(subscription, notificationWithSubscriptionId)
since.set(notification.id)
since.set(notification.timestamp)
}
}

View file

@ -5,6 +5,8 @@ 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
@ -356,7 +358,7 @@ class AddFragment : DialogFragment() {
activity.runOnUiThread {
val topic = subscribeTopicText.text.toString()
val baseUrl = getBaseUrl()
val instant = !BuildConfig.FIREBASE_AVAILABLE || baseUrl != appBaseUrl || subscribeInstantDeliveryCheckbox.isChecked
val instant = !BuildConfig.FIREBASE_AVAILABLE || baseUrl != appBaseUrl
subscribeListener.onSubscribe(topic, baseUrl, instant)
dialog?.dismiss()
}

View file

@ -9,17 +9,13 @@ import io.heckel.ntfy.R
fun initBaseUrlDropdown(baseUrls: List<String>, textView: AutoCompleteTextView, layout: TextInputLayout) {
// Base URL dropdown behavior; Oh my, why is this so complicated?!
val context = layout.context
val toggleEndIcon = {
if (textView.text.isNotEmpty()) {
layout.setEndIconDrawable(R.drawable.ic_cancel_gray_24dp)
layout.endIconContentDescription = context.getString(R.string.add_dialog_base_urls_dropdown_clear)
} else if (baseUrls.isEmpty()) {
layout.setEndIconDrawable(0)
layout.endIconContentDescription = ""
} else {
layout.setEndIconDrawable(R.drawable.ic_drop_down_gray_24dp)
layout.endIconContentDescription = context.getString(R.string.add_dialog_base_urls_dropdown_choose)
}
}
layout.setEndIconOnClickListener {
@ -27,14 +23,11 @@ fun initBaseUrlDropdown(baseUrls: List<String>, textView: AutoCompleteTextView,
textView.text.clear()
if (baseUrls.isEmpty()) {
layout.setEndIconDrawable(0)
layout.endIconContentDescription = ""
} else {
layout.setEndIconDrawable(R.drawable.ic_drop_down_gray_24dp)
layout.endIconContentDescription = context.getString(R.string.add_dialog_base_urls_dropdown_choose)
}
} else if (textView.text.isEmpty() && baseUrls.isNotEmpty()) {
layout.setEndIconDrawable(R.drawable.ic_drop_up_gray_24dp)
layout.endIconContentDescription = context.getString(R.string.add_dialog_base_urls_dropdown_choose)
textView.showDropDown()
}
}
@ -56,13 +49,10 @@ fun initBaseUrlDropdown(baseUrls: List<String>, textView: AutoCompleteTextView,
textView.setAdapter(adapter)
if (baseUrls.count() == 1) {
layout.setEndIconDrawable(R.drawable.ic_cancel_gray_24dp)
layout.endIconContentDescription = context.getString(R.string.add_dialog_base_urls_dropdown_clear)
textView.setText(baseUrls.first())
} else if (baseUrls.count() > 1) {
layout.setEndIconDrawable(R.drawable.ic_drop_down_gray_24dp)
layout.endIconContentDescription = context.getString(R.string.add_dialog_base_urls_dropdown_choose)
} else {
layout.setEndIconDrawable(0)
layout.endIconContentDescription = ""
}
}

View file

@ -1,44 +1,24 @@
package io.heckel.ntfy.ui
import android.content.Context
import androidx.core.content.ContextCompat
import io.heckel.ntfy.R
import io.heckel.ntfy.util.isDarkThemeOn
class Colors {
companion object {
const val refreshProgressIndicator = R.color.teal
fun notificationIcon(context: Context): Int {
return if (isDarkThemeOn(context)) R.color.teal_light else R.color.teal
}
const val notificationIcon = R.color.teal
fun itemSelectedBackground(context: Context): Int {
return if (isDarkThemeOn(context)) R.color.black_800b else R.color.gray_400
}
fun cardBackground(context: Context): Int {
return if (isDarkThemeOn(context)) R.color.black_800b else R.color.white
}
fun cardSelectedBackground(context: Context): Int {
return if (isDarkThemeOn(context)) R.color.black_700b else R.color.gray_500
}
fun cardBackgroundColor(context: Context): Int {
return ContextCompat.getColor(context, cardBackground(context))
}
fun cardSelectedBackgroundColor(context: Context): Int {
return ContextCompat.getColor(context, cardSelectedBackground(context))
return if (isDarkThemeOn(context)) R.color.gray_dark else R.color.gray_light
}
fun statusBarNormal(context: Context): Int {
return if (isDarkThemeOn(context)) R.color.black_900 else R.color.teal
return if (isDarkThemeOn(context)) R.color.black_light else R.color.teal
}
fun statusBarActionMode(context: Context): Int {
return if (isDarkThemeOn(context)) R.color.black_900 else R.color.teal_dark
return if (isDarkThemeOn(context)) R.color.black_light else R.color.teal_dark
}
fun dangerText(context: Context): Int {

View file

@ -7,9 +7,9 @@ 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.util.Base64
import android.view.ActionMode
import android.view.Menu
import android.view.MenuItem
@ -33,6 +33,7 @@ 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.MESSAGE_ENCODING_BASE64
import io.heckel.ntfy.msg.NotificationService
import io.heckel.ntfy.service.SubscriberServiceManager
import io.heckel.ntfy.util.*
@ -55,7 +56,6 @@ 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!
@ -101,26 +101,18 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
val topic = url.pathSegments.first()
title = topicShortUrl(baseUrl, topic)
// Subscribe to topic if it doesn't already exist
lifecycleScope.launch(Dispatchers.IO) {
var subscription = repository.getSubscription(baseUrl, topic)
if (subscription == null) {
val instant = baseUrl != appBaseUrl
subscription = Subscription(
id = randomSubscriptionId(),
id = Random.nextLong(),
baseUrl = baseUrl,
topic = topic,
instant = instant,
dedicatedChannels = false,
mutedUntil = 0,
minPriority = Repository.MIN_PRIORITY_USE_GLOBAL,
autoDelete = Repository.AUTO_DELETE_USE_GLOBAL,
insistent = Repository.INSISTENT_MAX_PRIORITY_USE_GLOBAL,
lastNotificationId = null,
icon = null,
upAppId = null,
upConnectorToken = null,
displayName = null,
totalCount = 0,
newCount = 0,
lastActive = Date().time/1000
@ -148,11 +140,9 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
}
}
// Add extras needed in loadView(); normally these are added in MainActivity
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)
@ -167,21 +157,20 @@ 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 = subscriptionDisplayName
title = topicUrl
// Set "how to instructions"
val howToExample: TextView = findViewById(R.id.detail_how_to_example)
howToExample.linksClickable = true
val howToText = getString(R.string.detail_how_to_example, topicUrl)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
howToExample.text = Html.fromHtml(howToText, Html.FROM_HTML_MODE_LEGACY)
} else {
howToExample.text = Html.fromHtml(howToText)
@ -197,7 +186,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
val onNotificationClick = { n: Notification -> onNotificationClick(n) }
val onNotificationLongClick = { n: Notification -> onNotificationLongClick(n) }
adapter = DetailAdapter(this, lifecycleScope, repository, onNotificationClick, onNotificationLongClick)
adapter = DetailAdapter(this, repository, onNotificationClick, onNotificationLongClick)
mainList = findViewById(R.id.detail_notification_list)
mainList.adapter = adapter
@ -244,7 +233,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 0, scrolling to the top")
Log.d(TAG, "$itemCount item(s) inserted at $positionStart, scrolling to the top")
mainList.scrollToPosition(positionStart)
}
}
@ -256,33 +245,15 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
}
// Mark this subscription as "open" so we don't receive notifications for it
Log.d(TAG, "onCreate hook: Marking subscription $subscriptionId as 'open'")
repository.detailViewSubscriptionId.set(subscriptionId)
// Stop insistent playback (if running, otherwise it'll throw)
try {
repository.mediaPlayer.stop()
} catch (_: Exception) {
// Ignore errors
}
}
override fun onResume() {
super.onResume()
// Mark as "open" so we don't send notifications while this is open
repository.detailViewSubscriptionId.set(subscriptionId)
// Update buttons (this is for when we return from the preferences screen)
lifecycleScope.launch(Dispatchers.IO) {
val subscription = repository.getSubscription(subscriptionId) ?: return@launch
subscriptionInstant = subscription.instant
subscriptionMutedUntil = subscription.mutedUntil
subscriptionDisplayName = displayName(subscription)
showHideInstantMenuItems(subscriptionInstant)
showHideMutedUntilMenuItems(subscriptionMutedUntil)
updateTitle(subscriptionDisplayName)
}
Log.d(TAG, "onResume hook: Marking subscription $subscriptionId as 'open'")
repository.detailViewSubscriptionId.set(subscriptionId) // Mark as "open" so we don't send notifications while this is open
}
override fun onPause() {
@ -315,7 +286,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
// Show and hide buttons
showHideInstantMenuItems(subscriptionInstant)
showHideMutedUntilMenuItems(subscriptionMutedUntil)
showHideNotificationMenuItems(subscriptionMutedUntil)
// Regularly check if "notification muted" time has passed
// NOTE: This is done here, because then we know that we've initialized the menu items.
@ -325,8 +296,6 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
}
private fun startNotificationMutedChecker() {
// FIXME This is awful and has to go.
lifecycleScope.launch(Dispatchers.IO) {
delay(1000) // Just to be sure we've initialized all the things, we wait a bit ...
while (isActive) {
@ -336,7 +305,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
if (mutedUntilExpired) {
val newSubscription = subscription.copy(mutedUntil = 0L)
repository.updateSubscription(newSubscription)
showHideMutedUntilMenuItems(0L)
showHideNotificationMenuItems(0L)
}
delay(60_000)
}
@ -377,10 +346,10 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
onClearClick()
true
}
R.id.detail_menu_settings -> {
/*R.id.detail_menu_settings -> {
onSettingsClick()
true
}
}*/
R.id.detail_menu_unsubscribe -> {
onDeleteClick()
true
@ -441,7 +410,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
val newSubscription = subscription?.copy(mutedUntil = mutedUntilTimestamp)
newSubscription?.let { repository.updateSubscription(newSubscription) }
subscriptionMutedUntil = mutedUntilTimestamp
showHideMutedUntilMenuItems(mutedUntilTimestamp)
showHideNotificationMenuItems(mutedUntilTimestamp)
runOnUiThread {
when (mutedUntilTimestamp) {
0L -> Toast.makeText(this@DetailActivity, getString(R.string.notification_dialog_enabled_toast_message), Toast.LENGTH_LONG).show()
@ -474,9 +443,8 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
lifecycleScope.launch(Dispatchers.IO) {
try {
val subscription = repository.getSubscription(subscriptionId) ?: return@launch
val user = repository.getUser(subscription.baseUrl) // May be null
val notifications = api.poll(subscription.id, subscription.baseUrl, subscription.topic, user, subscription.lastNotificationId)
val user = repository.getUser(subscriptionBaseUrl) // May be null
val notifications = api.poll(subscriptionId, subscriptionBaseUrl, subscriptionTopic, user)
val newNotifications = repository.onlyNewNotifications(subscriptionId, notifications)
val toastMessage = if (newNotifications.isEmpty()) {
getString(R.string.refresh_message_no_results)
@ -521,9 +489,6 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
}
private fun showHideInstantMenuItems(enable: Boolean) {
if (!this::menu.isInitialized) {
return
}
subscriptionInstant = enable
runOnUiThread {
val appBaseUrl = getString(R.string.app_base_url)
@ -540,10 +505,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
}
}
private fun showHideMutedUntilMenuItems(mutedUntilTimestamp: Long) {
if (!this::menu.isInitialized) {
return
}
private fun showHideNotificationMenuItems(mutedUntilTimestamp: Long) {
subscriptionMutedUntil = mutedUntilTimestamp
runOnUiThread {
val notificationsEnabledItem = menu.findItem(R.id.detail_menu_notifications_enabled)
@ -559,12 +521,6 @@ 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)}")
@ -581,7 +537,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
dialog.setOnShowListener {
dialog
.getButton(AlertDialog.BUTTON_POSITIVE)
.dangerButton(this)
.setTextAppearance(R.style.DangerText)
}
dialog.show()
}
@ -591,9 +547,6 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
val intent = Intent(this, DetailSettingsActivity::class.java)
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)
}
@ -619,7 +572,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
dialog.setOnShowListener {
dialog
.getButton(AlertDialog.BUTTON_POSITIVE)
.dangerButton(this)
.setTextAppearance(R.style.DangerText)
}
dialog.show()
}
@ -629,12 +582,12 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
handleActionModeClick(notification)
} else if (notification.click != "") {
try {
startActivity(Intent(ACTION_VIEW, Uri.parse(notification.click)))
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(notification.click)))
} catch (e: Exception) {
Log.w(TAG, "Cannot open click URL", e)
runOnUiThread {
Toast
.makeText(this@DetailActivity, getString(R.string.detail_item_cannot_open_url, e.message), Toast.LENGTH_LONG)
.makeText(this@DetailActivity, getString(R.string.detail_item_cannot_open_click_url, e.message), Toast.LENGTH_LONG)
.show()
}
}
@ -661,6 +614,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
finishActionMode()
} else {
actionMode!!.title = adapter.selected.size.toString()
redrawList()
}
}
@ -730,7 +684,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
dialog.setOnShowListener {
dialog
.getButton(AlertDialog.BUTTON_POSITIVE)
.dangerButton(this)
.setTextAppearance(R.style.DangerText)
}
dialog.show()
}
@ -741,7 +695,8 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
private fun beginActionMode(notification: Notification) {
actionMode = startActionMode(this)
adapter.toggleSelection(notification.id)
adapter.selected.add(notification.id)
redrawList()
// Fade status bar color
val fromColor = ContextCompat.getColor(this, Colors.statusBarNormal(this))
@ -757,7 +712,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
private fun endActionModeAndRedraw() {
actionMode = null
adapter.selected.clear()
adapter.notifyItemRangeChanged(0, adapter.currentList.size)
redrawList()
// Fade status bar color
val fromColor = ContextCompat.getColor(this, Colors.statusBarActionMode(this))
@ -765,11 +720,12 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
fadeStatusBarColor(window, fromColor, toColor)
}
private fun redrawList() {
mainList.adapter = adapter // Oh, what a hack ...
}
companion object {
const val TAG = "NtfyDetailActivity"
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

@ -5,6 +5,7 @@ import android.app.Activity
import android.content.*
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Build
import android.os.Environment
@ -13,32 +14,23 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.cardview.widget.CardView
import androidx.constraintlayout.helper.widget.Flow
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import androidx.core.view.allViews
import androidx.recyclerview.widget.DiffUtil
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.R
import io.heckel.ntfy.db.*
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.msg.DownloadWorker
import io.heckel.ntfy.util.*
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) :
class DetailAdapter(private val activity: Activity, private val repository: Repository, private val onClick: (Notification) -> Unit, private val onLongClick: (Notification) -> Unit) :
ListAdapter<Notification, DetailAdapter.DetailViewHolder>(TopicDiffCallback) {
val selected = mutableSetOf<String>() // Notification IDs
@ -46,7 +38,7 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DetailViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.fragment_detail_item, parent, false)
return DetailViewHolder(activity, lifecycleScope, repository, view, selected, onClick, onLongClick)
return DetailViewHolder(activity, repository, view, selected, onClick, onLongClick)
}
/* Gets current topic and uses it to bind view. */
@ -64,25 +56,16 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope:
} else {
selected.add(notificationId)
}
if (selected.size != 0) {
val listIds = currentList.map { notification -> notification.id }
val notificationPosition = listIds.indexOf(notificationId)
notifyItemChanged(notificationPosition)
}
}
/* ViewHolder for Topic, takes in the inflated view and the onClick behavior. */
class DetailViewHolder(private val activity: Activity, private val lifecycleScope: CoroutineScope, private val repository: Repository, itemView: View, private val selected: Set<String>, val onClick: (Notification) -> Unit, val onLongClick: (Notification) -> Unit) :
class DetailViewHolder(private val activity: Activity, private val repository: Repository, itemView: View, private val selected: Set<String>, val onClick: (Notification) -> Unit, val onLongClick: (Notification) -> Unit) :
RecyclerView.ViewHolder(itemView) {
private var notification: Notification? = null
private val layout: View = itemView.findViewById(R.id.detail_item_layout)
private val cardView: CardView = itemView.findViewById(R.id.detail_item_card)
private val priorityImageView: ImageView = itemView.findViewById(R.id.detail_item_priority_image)
private val dateView: TextView = itemView.findViewById(R.id.detail_item_date_text)
private val titleView: TextView = itemView.findViewById(R.id.detail_item_title_text)
private val messageView: TextView = itemView.findViewById(R.id.detail_item_message_text)
private val iconView: ImageView = itemView.findViewById(R.id.detail_item_icon)
private val newDotImageView: View = itemView.findViewById(R.id.detail_item_new_dot)
private val tagsView: TextView = itemView.findViewById(R.id.detail_item_tags_text)
private val menuButton: ImageButton = itemView.findViewById(R.id.detail_item_menu_button)
@ -90,8 +73,6 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope:
private val attachmentBoxView: View = itemView.findViewById(R.id.detail_item_attachment_file_box)
private val attachmentIconView: ImageView = itemView.findViewById(R.id.detail_item_attachment_file_icon)
private val attachmentInfoView: TextView = itemView.findViewById(R.id.detail_item_attachment_file_info)
private val actionsWrapperView: ConstraintLayout = itemView.findViewById(R.id.detail_item_actions_wrapper)
private val actionsFlow: Flow = itemView.findViewById(R.id.detail_item_actions_flow)
fun bind(notification: Notification) {
this.notification = notification
@ -100,21 +81,10 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope:
val unmatchedTags = unmatchedTags(splitTags(notification.tags))
dateView.text = formatDateShort(notification.timestamp)
messageView.text = maybeAppendActionErrors(formatMessage(notification), notification)
messageView.setOnClickListener {
// Click & Long-click listeners on the text as well, because "autoLink=web" makes them
// clickable, and so we cannot rely on the underlying card to perform the action.
// It's weird because "layout" is the ripple-able, but the card is clickable.
// See https://github.com/binwiederhier/ntfy/issues/226
layout.ripple(lifecycleScope)
onClick(notification)
}
messageView.setOnLongClickListener {
onLongClick(notification); true
}
messageView.text = formatMessage(notification)
newDotImageView.visibility = if (notification.notificationId == 0) View.GONE else View.VISIBLE
cardView.setOnClickListener { onClick(notification) }
cardView.setOnLongClickListener { onLongClick(notification); true }
itemView.setOnClickListener { onClick(notification) }
itemView.setOnLongClickListener { onLongClick(notification); true }
if (notification.title != "") {
titleView.visibility = View.VISIBLE
titleView.text = formatTitle(notification)
@ -128,75 +98,53 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope:
tagsView.visibility = View.GONE
}
if (selected.contains(notification.id)) {
cardView.setCardBackgroundColor(Colors.cardSelectedBackgroundColor(context))
} else {
cardView.setCardBackgroundColor(Colors.cardBackgroundColor(context))
itemView.setBackgroundResource(Colors.itemSelectedBackground(context))
}
val attachment = notification.attachment
val attachmentFileStat = maybeFileStat(context, attachment?.contentUri)
val iconFileStat = maybeFileStat(context, notification.icon?.contentUri)
val exists = if (attachment?.contentUri != null) fileExists(context, attachment.contentUri) else false
renderPriority(context, notification)
resetCardButtons()
maybeRenderMenu(context, notification, attachmentFileStat)
maybeRenderAttachment(context, notification, attachmentFileStat)
maybeRenderIcon(context, notification, iconFileStat)
maybeRenderActions(context, notification)
maybeRenderMenu(context, notification, exists)
maybeRenderAttachment(context, notification, exists)
}
private fun renderPriority(context: Context, notification: Notification) {
when (notification.priority) {
PRIORITY_MIN -> {
1 -> {
priorityImageView.visibility = View.VISIBLE
priorityImageView.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_priority_1_24dp))
}
PRIORITY_LOW -> {
2 -> {
priorityImageView.visibility = View.VISIBLE
priorityImageView.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_priority_2_24dp))
}
PRIORITY_DEFAULT -> {
3 -> {
priorityImageView.visibility = View.GONE
}
PRIORITY_HIGH -> {
4 -> {
priorityImageView.visibility = View.VISIBLE
priorityImageView.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_priority_4_24dp))
}
PRIORITY_MAX -> {
5 -> {
priorityImageView.visibility = View.VISIBLE
priorityImageView.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_priority_5_24dp))
}
}
}
private fun maybeRenderAttachment(context: Context, notification: Notification, attachmentFileStat: FileInfo?) {
private fun maybeRenderAttachment(context: Context, notification: Notification, exists: Boolean) {
if (notification.attachment == null) {
attachmentImageView.visibility = View.GONE
attachmentBoxView.visibility = View.GONE
return
}
val attachment = notification.attachment
val image = attachment.contentUri != null && supportedImage(attachment.type) && previewableImage(attachmentFileStat)
val bitmap = if (image) attachment.contentUri?.readBitmapFromUriOrNull(context) else null
maybeRenderAttachmentImage(context, bitmap)
maybeRenderAttachmentBox(context, notification, attachment, attachmentFileStat, bitmap)
val image = attachment.contentUri != null && exists && supportedImage(attachment.type)
maybeRenderAttachmentImage(context, attachment, image)
maybeRenderAttachmentBox(context, notification, attachment, exists, image)
}
private fun maybeRenderIcon(context: Context, notification: Notification, iconStat: FileInfo?) {
if (notification.icon == null || !previewableImage(iconStat)) {
iconView.visibility = View.GONE
return
}
try {
val icon = notification.icon
val bitmap = icon.contentUri?.readBitmapFromUri(context) ?: throw Exception("uri empty")
iconView.setImageBitmap(bitmap)
iconView.visibility = View.VISIBLE
} catch (_: Exception) {
iconView.visibility = View.GONE
}
}
private fun maybeRenderMenu(context: Context, notification: Notification, attachmentFileStat: FileInfo?) {
val menuButtonPopupMenu = maybeCreateMenuPopup(context, menuButton, notification, attachmentFileStat) // Heavy lifting not during on-click
private fun maybeRenderMenu(context: Context, notification: Notification, exists: Boolean) {
val menuButtonPopupMenu = maybeCreateMenuPopup(context, menuButton, notification, exists) // Heavy lifting not during on-click
if (menuButtonPopupMenu != null) {
menuButton.setOnClickListener { menuButtonPopupMenu.show() }
menuButton.visibility = View.VISIBLE
@ -205,50 +153,14 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope:
}
}
private fun maybeRenderActions(context: Context, notification: Notification) {
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) {
val action = notification.actions[i]
val label = formatActionLabel(action)
val actionButton = createCardButton(context, label) { runAction(context, notification, action) }
addButtonToCard(actionButton)
}
} else {
actionsWrapperView.visibility = View.GONE
}
}
private fun resetCardButtons() {
// clear any previously created dynamic buttons
actionsFlow.allViews.forEach { actionsFlow.removeView(it) }
actionsWrapperView.removeAllViews()
actionsWrapperView.addView(actionsFlow)
}
private fun addButtonToCard(button: View) {
actionsWrapperView.addView(button)
actionsFlow.addView(button)
}
private fun createCardButton(context: Context, label: String, onClick: () -> Boolean): View {
// See https://stackoverflow.com/a/41139179/1440785
val button = LayoutInflater.from(context).inflate(R.layout.button_action, null) as MaterialButton
button.id = View.generateViewId()
button.text = label
button.setOnClickListener { onClick() }
return button
}
private fun maybeRenderAttachmentBox(context: Context, notification: Notification, attachment: Attachment, attachmentFileStat: FileInfo?, bitmap: Bitmap?) {
if (bitmap != null) {
private fun maybeRenderAttachmentBox(context: Context, notification: Notification, attachment: Attachment, exists: Boolean, image: Boolean) {
if (image) {
attachmentBoxView.visibility = View.GONE
return
}
attachmentInfoView.text = formatAttachmentDetails(context, attachment, attachmentFileStat)
attachmentInfoView.text = formatAttachmentDetails(context, attachment, exists)
attachmentIconView.setImageResource(mimeTypeToIconResource(attachment.type))
val attachmentBoxPopupMenu = maybeCreateMenuPopup(context, attachmentBoxView, notification, attachmentFileStat) // Heavy lifting not during on-click
val attachmentBoxPopupMenu = maybeCreateMenuPopup(context, attachmentBoxView, notification, exists) // Heavy lifting not during on-click
if (attachmentBoxPopupMenu != null) {
attachmentBoxView.setOnClickListener { attachmentBoxPopupMenu.show() }
} else {
@ -261,12 +173,11 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope:
attachmentBoxView.visibility = View.VISIBLE
}
private fun maybeCreateMenuPopup(context: Context, anchor: View?, notification: Notification, attachmentFileStat: FileInfo?): PopupMenu? {
private fun maybeCreateMenuPopup(context: Context, anchor: View?, notification: Notification, exists: Boolean): PopupMenu? {
val popup = PopupMenu(context, anchor)
popup.menuInflater.inflate(R.menu.menu_detail_attachment, popup.menu)
val attachment = notification.attachment // May be null
val hasAttachment = attachment != null
val attachmentExists = attachmentFileStat != null
val hasClickLink = notification.click != ""
val downloadItem = popup.menu.findItem(R.id.detail_item_menu_download)
val cancelItem = popup.menu.findItem(R.id.detail_item_menu_cancel)
@ -288,10 +199,10 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope:
if (hasClickLink) {
copyContentsItem.setOnMenuItemClickListener { copyContents(context, notification) }
}
openItem.isVisible = hasAttachment && attachmentExists
downloadItem.isVisible = hasAttachment && !attachmentExists && !expired && !inProgress
deleteItem.isVisible = hasAttachment && attachmentExists
saveFileItem.isVisible = hasAttachment && attachmentExists
openItem.isVisible = hasAttachment && exists
downloadItem.isVisible = hasAttachment && !exists && !expired && !inProgress
deleteItem.isVisible = hasAttachment && exists
saveFileItem.isVisible = hasAttachment && exists
copyUrlItem.isVisible = hasAttachment && !expired
cancelItem.isVisible = hasAttachment && inProgress
copyContentsItem.isVisible = notification.click != ""
@ -304,13 +215,12 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope:
return popup
}
private fun formatAttachmentDetails(context: Context, attachment: Attachment, attachmentFileStat: FileInfo?): String {
private fun formatAttachmentDetails(context: Context, attachment: Attachment, exists: Boolean): String {
val name = attachment.name
val exists = attachmentFileStat != null
val notYetDownloaded = !exists && attachment.progress == ATTACHMENT_PROGRESS_NONE
val notYetDownloaded = !exists && attachment.progress == PROGRESS_NONE
val downloading = !exists && attachment.progress in 0..99
val deleted = !exists && (attachment.progress == ATTACHMENT_PROGRESS_DONE || attachment.progress == ATTACHMENT_PROGRESS_DELETED)
val failed = !exists && attachment.progress == ATTACHMENT_PROGRESS_FAILED
val deleted = !exists && (attachment.progress == PROGRESS_DONE || attachment.progress == PROGRESS_DELETED)
val failed = !exists && attachment.progress == PROGRESS_FAILED
val expired = attachment.expires != null && attachment.expires < System.currentTimeMillis()/1000
val expires = attachment.expires != null && attachment.expires > System.currentTimeMillis()/1000
val infos = mutableListOf<String>()
@ -351,12 +261,15 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope:
}
}
private fun maybeRenderAttachmentImage(context: Context, bitmap: Bitmap?) {
if (bitmap == null) {
private fun maybeRenderAttachmentImage(context: Context, attachment: Attachment, image: Boolean) {
if (!image) {
attachmentImageView.visibility = View.GONE
return
}
try {
val resolver = context.applicationContext.contentResolver
val bitmapStream = resolver.openInputStream(Uri.parse(attachment.contentUri))
val bitmap = BitmapFactory.decodeStream(bitmapStream)
attachmentImageView.setImageBitmap(bitmap)
attachmentImageView.setOnClickListener {
val loadImage = { view: ImageView, image: Bitmap -> view.setImageBitmap(image) }
@ -373,12 +286,6 @@ 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)
@ -417,7 +324,7 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope:
val inFile = resolver.openInputStream(inUri) ?: throw Exception("Cannot open input stream")
val outUri = if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
val file = ensureSafeNewFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), attachment.name)
FileProvider.getUriForFile(context, DownloadAttachmentWorker.FILE_PROVIDER_AUTHORITY, file)
FileProvider.getUriForFile(context, DownloadWorker.FILE_PROVIDER_AUTHORITY, file)
} else {
val contentUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL)
resolver.insert(contentUri, values) ?: throw Exception("Cannot insert content")
@ -450,7 +357,7 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope:
if (!deleted) throw Exception("no rows deleted")
val newAttachment = attachment.copy(
contentUri = null,
progress = ATTACHMENT_PROGRESS_DELETED
progress = PROGRESS_DELETED
)
val newNotification = notification.copy(attachment = newAttachment)
GlobalScope.launch(Dispatchers.IO) {
@ -471,7 +378,7 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope:
ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_CODE_WRITE_STORAGE_PERMISSION_FOR_DOWNLOAD)
return true
}
DownloadManager.enqueue(context, notification.id, userAction = true, DownloadType.ATTACHMENT)
DownloadManager.enqueue(context, notification.id, userAction = true)
return true
}
@ -494,43 +401,6 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope:
copyToClipboard(context, notification)
return true
}
private fun runAction(context: Context, notification: Notification, action: Action): Boolean {
when (action.action) {
ACTION_VIEW -> runViewAction(context, action)
else -> runOtherUserAction(context, notification, action)
}
return true
}
private fun runViewAction(context: Context, action: Action) {
try {
val url = action.url ?: return
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply {
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
context.startActivity(intent)
} catch (e: Exception) {
Log.w(TAG, "Unable to start activity from URL ${action.url}", e)
val message = if (e is ActivityNotFoundException) action.url else e.message
Toast
.makeText(context, context.getString(R.string.detail_item_cannot_open_url, message), Toast.LENGTH_LONG)
.show()
}
}
private fun runOtherUserAction(context: Context, notification: Notification, action: Action) {
val intent = Intent(context, NotificationService.UserActionBroadcastReceiver::class.java).apply {
putExtra(NotificationService.BROADCAST_EXTRA_TYPE, NotificationService.BROADCAST_TYPE_USER_ACTION)
putExtra(NotificationService.BROADCAST_EXTRA_NOTIFICATION_ID, notification.id)
putExtra(NotificationService.BROADCAST_EXTRA_ACTION_ID, action.id)
}
context.sendBroadcast(intent)
}
private fun previewableImage(fileStat: FileInfo?): Boolean {
return if (fileStat != null) fileStat.size <= IMAGE_PREVIEW_MAX_BYTES else false
}
}
object TopicDiffCallback : DiffUtil.ItemCallback<Notification>() {
@ -546,6 +416,5 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope:
companion object {
const val TAG = "NtfyDetailAdapter"
const val REQUEST_CODE_WRITE_STORAGE_PERMISSION_FOR_DOWNLOAD = 9876
const val IMAGE_PREVIEW_MAX_BYTES = 5 * 1024 * 1024 // Too large images crash the app with "Canvas: trying to draw too large(233280000bytes) bitmap."
}
}

View file

@ -1,44 +1,26 @@
package io.heckel.ntfy.ui
import android.content.ContentResolver
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import android.text.TextUtils
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import androidx.core.graphics.drawable.toDrawable
import androidx.lifecycle.lifecycleScope
import androidx.preference.*
import androidx.preference.Preference.OnPreferenceClickListener
import io.heckel.ntfy.BuildConfig
import androidx.preference.PreferenceFragmentCompat
import io.heckel.ntfy.R
import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.db.Subscription
import io.heckel.ntfy.msg.DownloadAttachmentWorker
import io.heckel.ntfy.msg.NotificationService
import io.heckel.ntfy.util.Log
import io.heckel.ntfy.service.SubscriberServiceManager
import io.heckel.ntfy.util.*
import kotlinx.coroutines.*
import java.io.File
import java.io.IOException
import java.util.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
/**
* Subscription settings
*
* THIS IS CURRENTLY UNUSED.
*/
class DetailSettingsActivity : AppCompatActivity() {
private lateinit var repository: Repository
private lateinit var serviceManager: SubscriberServiceManager
private lateinit var settingsFragment: SettingsFragment
private lateinit var notificationService: NotificationService
private var subscriptionId: Long = 0
override fun onCreate(savedInstanceState: Bundle?) {
@ -49,7 +31,6 @@ class DetailSettingsActivity : AppCompatActivity() {
repository = Repository.getInstance(this)
serviceManager = SubscriberServiceManager(this)
notificationService = NotificationService(this)
subscriptionId = intent.getLongExtra(DetailActivity.EXTRA_SUBSCRIPTION_ID, 0)
if (savedInstanceState == null) {
@ -63,9 +44,7 @@ class DetailSettingsActivity : AppCompatActivity() {
.commit()
}
// Title
val displayName = intent.getStringExtra(DetailActivity.EXTRA_SUBSCRIPTION_DISPLAY_NAME) ?: return
title = displayName
title = getString(R.string.detail_settings_title)
// Show 'Back' button
supportActionBar?.setDisplayHomeAsUpEnabled(true)
@ -77,16 +56,8 @@ class DetailSettingsActivity : AppCompatActivity() {
}
class SettingsFragment : PreferenceFragmentCompat() {
private lateinit var resolver: ContentResolver
private lateinit var repository: Repository
private lateinit var serviceManager: SubscriberServiceManager
private lateinit var notificationService: NotificationService
private lateinit var subscription: Subscription
private lateinit var iconSetPref: Preference
private lateinit var openChannelsPref: Preference
private lateinit var iconSetLauncher: ActivityResultLauncher<String>
private lateinit var iconRemovePref: Preference
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.detail_preferences, rootKey)
@ -94,426 +65,23 @@ class DetailSettingsActivity : AppCompatActivity() {
// Dependencies (Fragments need a default constructor)
repository = Repository.getInstance(requireActivity())
serviceManager = SubscriberServiceManager(requireActivity())
notificationService = NotificationService(requireActivity())
resolver = requireContext().applicationContext.contentResolver
// Create result launcher for custom icon (must be created in onCreatePreferences() directly)
iconSetLauncher = createIconPickLauncher()
// Load subscription and users
val subscriptionId = arguments?.getLong(DetailActivity.EXTRA_SUBSCRIPTION_ID) ?: return
runBlocking {
withContext(Dispatchers.IO) {
subscription = repository.getSubscription(subscriptionId) ?: return@withContext
activity?.runOnUiThread {
loadView()
}
}
}
}
private fun loadView() {
if (subscription.upAppId == null) {
loadInstantPref()
loadMutedUntilPref()
loadMinPriorityPref()
loadAutoDeletePref()
loadInsistentMaxPriorityPref()
loadIconSetPref()
loadIconRemovePref()
if (notificationService.channelsSupported()) {
loadDedicatedChannelsPrefs()
loadOpenChannelsPrefs()
}
} else {
val notificationsHeaderId = context?.getString(R.string.detail_settings_notifications_header_key) ?: return
val notificationsHeader: PreferenceCategory? = findPreference(notificationsHeaderId)
notificationsHeader?.isVisible = false
}
loadDisplayNamePref()
loadTopicUrlPref()
}
private fun loadInstantPref() {
val appBaseUrl = getString(R.string.app_base_url)
val prefId = context?.getString(R.string.detail_settings_notifications_instant_key) ?: return
val pref: SwitchPreference? = findPreference(prefId)
pref?.isVisible = BuildConfig.FIREBASE_AVAILABLE && subscription.baseUrl == appBaseUrl
pref?.isChecked = subscription.instant
pref?.preferenceDataStore = object : PreferenceDataStore() {
override fun putBoolean(key: String?, value: Boolean) {
save(subscription.copy(instant = value), refresh = true)
}
override fun getBoolean(key: String?, defValue: Boolean): Boolean {
return subscription.instant
}
}
pref?.summaryProvider = Preference.SummaryProvider<SwitchPreference> { preference ->
if (preference.isChecked) {
getString(R.string.detail_settings_notifications_instant_summary_on)
} else {
getString(R.string.detail_settings_notifications_instant_summary_off)
}
}
}
private fun loadDedicatedChannelsPrefs() {
val prefId = context?.getString(R.string.detail_settings_notifications_dedicated_channels_key) ?: return
val pref: SwitchPreference? = findPreference(prefId)
pref?.isVisible = true
pref?.isChecked = subscription.dedicatedChannels
pref?.preferenceDataStore = object : PreferenceDataStore() {
override fun putBoolean(key: String?, value: Boolean) {
save(subscription.copy(dedicatedChannels = value))
if (value) {
notificationService.createSubscriptionNotificationChannels(subscription)
} else {
notificationService.deleteSubscriptionNotificationChannels(subscription)
}
openChannelsPref.isVisible = value
}
override fun getBoolean(key: String?, defValue: Boolean): Boolean {
return subscription.dedicatedChannels
}
}
pref?.summaryProvider = Preference.SummaryProvider<SwitchPreference> { preference ->
if (preference.isChecked) {
getString(R.string.detail_settings_notifications_dedicated_channels_summary_on)
} else {
getString(R.string.detail_settings_notifications_dedicated_channels_summary_off)
}
}
}
private fun loadOpenChannelsPrefs() {
val prefId = context?.getString(R.string.detail_settings_notifications_open_channels_key) ?: return
openChannelsPref = findPreference(prefId) ?: return
openChannelsPref.isVisible = subscription.dedicatedChannels
openChannelsPref.preferenceDataStore = object : PreferenceDataStore() { } // Dummy store to protect from accidentally overwriting
openChannelsPref.onPreferenceClickListener = Preference.OnPreferenceClickListener { _ ->
val settingsIntent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(Settings.EXTRA_APP_PACKAGE, requireContext().applicationContext.packageName)
startActivity(settingsIntent);
true
}
}
private fun loadMutedUntilPref() {
val prefId = context?.getString(R.string.detail_settings_notifications_muted_until_key) ?: return
val pref: ListPreference? = findPreference(prefId)
pref?.isVisible = true // Hack: Show all settings at once, because subscription is loaded asynchronously
pref?.value = subscription.mutedUntil.toString()
pref?.preferenceDataStore = object : PreferenceDataStore() {
override fun putString(key: String?, value: String?) {
val mutedUntilValue = value?.toLongOrNull() ?:return
when (mutedUntilValue) {
Repository.MUTED_UNTIL_SHOW_ALL -> save(subscription.copy(mutedUntil = mutedUntilValue))
Repository.MUTED_UNTIL_FOREVER -> save(subscription.copy(mutedUntil = mutedUntilValue))
Repository.MUTED_UNTIL_TOMORROW -> {
val date = Calendar.getInstance()
date.add(Calendar.DAY_OF_MONTH, 1)
date.set(Calendar.HOUR_OF_DAY, 8)
date.set(Calendar.MINUTE, 30)
date.set(Calendar.SECOND, 0)
date.set(Calendar.MILLISECOND, 0)
save(subscription.copy(mutedUntil = date.timeInMillis/1000))
}
else -> {
val mutedUntilTimestamp = System.currentTimeMillis()/1000 + mutedUntilValue * 60
save(subscription.copy(mutedUntil = mutedUntilTimestamp))
}
}
}
override fun getString(key: String?, defValue: String?): String {
return subscription.mutedUntil.toString()
}
}
pref?.summaryProvider = Preference.SummaryProvider<ListPreference> {
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 -> {
val formattedDate = formatDateShort(mutedUntilValue)
getString(R.string.settings_notifications_muted_until_x, formattedDate)
}
}
}
}
private fun loadMinPriorityPref() {
val prefId = context?.getString(R.string.detail_settings_notifications_min_priority_key) ?: return
val pref: ListPreference? = findPreference(prefId)
pref?.isVisible = true // Hack: Show all settings at once, because subscription is loaded asynchronously
pref?.value = subscription.minPriority.toString()
pref?.preferenceDataStore = object : PreferenceDataStore() {
override fun putString(key: String?, value: String?) {
val minPriorityValue = value?.toIntOrNull() ?:return
save(subscription.copy(minPriority = minPriorityValue))
}
override fun getString(key: String?, defValue: String?): String {
return subscription.minPriority.toString()
}
}
pref?.summaryProvider = Preference.SummaryProvider<ListPreference> { preference ->
var value = preference.value.toIntOrNull() ?: Repository.MIN_PRIORITY_USE_GLOBAL
val global = value == Repository.MIN_PRIORITY_USE_GLOBAL
if (value == Repository.MIN_PRIORITY_USE_GLOBAL) {
value = repository.getMinPriority()
}
val summary = when (value) {
PRIORITY_MIN -> getString(R.string.settings_notifications_min_priority_summary_any)
PRIORITY_MAX -> getString(R.string.settings_notifications_min_priority_summary_max)
else -> {
val minPriorityString = toPriorityString(requireContext(), value)
getString(R.string.settings_notifications_min_priority_summary_x_or_higher, value, minPriorityString)
}
}
maybeAppendGlobal(summary, global)
}
}
private fun loadAutoDeletePref() {
val prefId = context?.getString(R.string.detail_settings_notifications_auto_delete_key) ?: return
val pref: ListPreference? = findPreference(prefId)
pref?.isVisible = true // Hack: Show all settings at once, because subscription is loaded asynchronously
pref?.value = subscription.autoDelete.toString()
pref?.preferenceDataStore = object : PreferenceDataStore() {
override fun putString(key: String?, value: String?) {
val seconds = value?.toLongOrNull() ?:return
save(subscription.copy(autoDelete = seconds))
}
override fun getString(key: String?, defValue: String?): String {
return subscription.autoDelete.toString()
}
}
pref?.summaryProvider = Preference.SummaryProvider<ListPreference> { preference ->
var seconds = preference.value.toLongOrNull() ?: Repository.AUTO_DELETE_USE_GLOBAL
val global = seconds == Repository.AUTO_DELETE_USE_GLOBAL
if (global) {
seconds = repository.getAutoDeleteSeconds()
}
val summary = when (seconds) {
Repository.AUTO_DELETE_NEVER -> getString(R.string.settings_notifications_auto_delete_summary_never)
Repository.AUTO_DELETE_ONE_DAY_SECONDS -> getString(R.string.settings_notifications_auto_delete_summary_one_day)
Repository.AUTO_DELETE_THREE_DAYS_SECONDS -> getString(R.string.settings_notifications_auto_delete_summary_three_days)
Repository.AUTO_DELETE_ONE_WEEK_SECONDS -> getString(R.string.settings_notifications_auto_delete_summary_one_week)
Repository.AUTO_DELETE_ONE_MONTH_SECONDS -> getString(R.string.settings_notifications_auto_delete_summary_one_month)
Repository.AUTO_DELETE_THREE_MONTHS_SECONDS -> getString(R.string.settings_notifications_auto_delete_summary_three_months)
else -> getString(R.string.settings_notifications_auto_delete_summary_one_month) // Must match default const
}
maybeAppendGlobal(summary, global)
}
}
private fun loadInsistentMaxPriorityPref() {
val prefId = context?.getString(R.string.detail_settings_notifications_insistent_max_priority_key) ?: return
val pref: ListPreference? = findPreference(prefId)
pref?.isVisible = true
pref?.value = subscription.insistent.toString()
pref?.preferenceDataStore = object : PreferenceDataStore() {
override fun putString(key: String?, value: String?) {
val intValue = value?.toIntOrNull() ?:return
save(subscription.copy(insistent = intValue))
}
override fun getString(key: String?, defValue: String?): String {
return subscription.insistent.toString()
}
}
pref?.summaryProvider = Preference.SummaryProvider<ListPreference> { preference ->
val value = preference.value.toIntOrNull() ?: Repository.INSISTENT_MAX_PRIORITY_USE_GLOBAL
val global = value == Repository.INSISTENT_MAX_PRIORITY_USE_GLOBAL
val enabled = if (global) repository.getInsistentMaxPriorityEnabled() else value == Repository.INSISTENT_MAX_PRIORITY_ENABLED
val summary = if (enabled) {
getString(R.string.settings_notifications_insistent_max_priority_summary_enabled)
} else {
getString(R.string.settings_notifications_insistent_max_priority_summary_disabled)
}
maybeAppendGlobal(summary, global)
}
}
private fun loadIconSetPref() {
val prefId = context?.getString(R.string.detail_settings_appearance_icon_set_key) ?: return
iconSetPref = findPreference(prefId) ?: return
iconSetPref.isVisible = subscription.icon == null
iconSetPref.preferenceDataStore = object : PreferenceDataStore() { } // Dummy store to protect from accidentally overwriting
iconSetPref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
iconSetLauncher.launch("image/*")
true
}
}
private fun loadIconRemovePref() {
val prefId = context?.getString(R.string.detail_settings_appearance_icon_remove_key) ?: return
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.isVisible = false
iconSetPref.isVisible = true
deleteIcon(subscription.icon)
save(subscription.copy(icon = null))
true
}
// Set icon (if it exists)
if (subscription.icon != null) {
try {
val bitmap = subscription.icon!!.readBitmapFromUri(requireContext())
iconRemovePref.icon = bitmap.toDrawable(resources)
} catch (e: Exception) {
Log.w(TAG, "Unable to set icon ${subscription.icon}", e)
}
}
}
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?.dialogMessage = getString(R.string.detail_settings_appearance_display_name_message, topicShortUrl(subscription.baseUrl, subscription.topic))
pref?.preferenceDataStore = object : PreferenceDataStore() {
override fun putString(key: String?, value: String?) {
val displayName = if (value != "") value else null
val newSubscription = subscription.copy(displayName = displayName)
save(newSubscription)
// Update activity title
activity?.runOnUiThread {
activity?.title = displayName(newSubscription)
}
// Update dedicated notification channel
if (newSubscription.dedicatedChannels) {
notificationService.createSubscriptionNotificationChannels(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 loadTopicUrlPref() {
// Topic URL
val topicUrlPrefId = context?.getString(R.string.detail_settings_about_topic_url_key) ?: return
val topicUrlPref: Preference? = findPreference(topicUrlPrefId)
val topicUrl = topicShortUrl(subscription.baseUrl, subscription.topic)
topicUrlPref?.summary = topicUrl
topicUrlPref?.onPreferenceClickListener = OnPreferenceClickListener {
val context = context ?: return@OnPreferenceClickListener false
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("topic url", topicUrl)
clipboard.setPrimaryClip(clip)
Toast
.makeText(context, getString(R.string.detail_settings_about_topic_url_copied_to_clipboard_message), Toast.LENGTH_LONG)
.show()
true
}
}
private fun createIconPickLauncher(): ActivityResultLauncher<String> {
return registerForActivityResult(ActivityResultContracts.GetContent()) { inputUri ->
if (inputUri == null) {
return@registerForActivityResult
}
lifecycleScope.launch(Dispatchers.IO) {
val outputUri = createUri() ?: return@launch
try {
// Early size & mime type check
val mimeType = resolver.getType(inputUri)
if (!supportedImage(mimeType)) {
throw IOException("unknown image type or not supported")
}
val stat = fileStat(requireContext(), inputUri) // May throw
if (stat.size > SUBSCRIPTION_ICON_MAX_SIZE_BYTES) {
throw IOException("image too large, max supported is ${SUBSCRIPTION_ICON_MAX_SIZE_BYTES/1024/1024}MB")
}
// Write to cache storage
val inputStream = resolver.openInputStream(inputUri) ?: throw IOException("Couldn't open content URI for reading")
val outputStream = resolver.openOutputStream(outputUri) ?: throw IOException("Couldn't open content URI for writing")
inputStream.use {
it.copyTo(outputStream)
}
// Read image, check dimensions
val bitmap = outputUri.readBitmapFromUri(requireContext())
if (bitmap.width > SUBSCRIPTION_ICON_MAX_WIDTH || bitmap.height > SUBSCRIPTION_ICON_MAX_HEIGHT) {
throw IOException("image exceeds max dimensions of ${SUBSCRIPTION_ICON_MAX_WIDTH}x${SUBSCRIPTION_ICON_MAX_HEIGHT}")
}
// Display "remove" preference
iconRemovePref.icon = bitmap.toDrawable(resources)
iconRemovePref.isVisible = true
iconSetPref.isVisible = false
// Finally, save (this is last!)
save(subscription.copy(icon = outputUri.toString()))
} catch (e: Exception) {
Log.w(TAG, "Saving icon failed", e)
requireActivity().runOnUiThread {
Toast.makeText(context, getString(R.string.detail_settings_appearance_icon_error_saving, e.message), Toast.LENGTH_LONG).show()
}
}
}
}
}
private fun createUri(): Uri? {
val dir = File(requireContext().cacheDir, SUBSCRIPTION_ICONS)
if (!dir.exists() && !dir.mkdirs()) {
return null
}
val file = File(dir, subscription.id.toString())
return FileProvider.getUriForFile(requireContext(), DownloadAttachmentWorker.FILE_PROVIDER_AUTHORITY, file)
}
private fun deleteIcon(uri: String?) {
if (uri == null) {
return
}
try {
resolver.delete(Uri.parse(uri), null, null)
} catch (e: Exception) {
Log.w(TAG, "Unable to delete $uri", e)
}
}
private fun save(newSubscription: Subscription, refresh: Boolean = false) {
subscription = newSubscription
lifecycleScope.launch(Dispatchers.IO) {
repository.updateSubscription(newSubscription)
if (refresh) {
SubscriberServiceManager.refresh(requireContext())
val subscription = repository.getSubscription(subscriptionId) ?: return@launch
activity?.runOnUiThread {
loadView(subscription)
}
}
}
private fun maybeAppendGlobal(summary: String, global: Boolean): String {
return if (global) {
summary + " (" + getString(R.string.detail_settings_global_setting_suffix) + ")"
} else {
summary
}
private fun loadView(subscription: Subscription) {
// ...
}
}
companion object {
private const val TAG = "NtfyDetailSettingsActiv"
private const val SUBSCRIPTION_ICONS = "subscriptionIcons"
private const val SUBSCRIPTION_ICON_MAX_SIZE_BYTES = 4194304
private const val SUBSCRIPTION_ICON_MAX_WIDTH = 2048
private const val SUBSCRIPTION_ICON_MAX_HEIGHT = 2048
}
}

View file

@ -21,7 +21,7 @@ class DetailViewModel(private val repository: Repository) : ViewModel() {
class DetailViewModelFactory(private val repository: Repository) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T =
override fun <T : ViewModel?> create(modelClass: Class<T>) =
with(modelClass){
when {
isAssignableFrom(DetailViewModel::class.java) -> DetailViewModel(repository) as T

View file

@ -1,28 +1,23 @@
package io.heckel.ntfy.ui
import android.Manifest
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.app.AlertDialog
import android.content.ActivityNotFoundException
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.text.method.LinkMovementMethod
import android.view.ActionMode
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView
@ -36,8 +31,6 @@ import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.db.Subscription
import io.heckel.ntfy.firebase.FirebaseMessenger
import io.heckel.ntfy.msg.ApiService
import io.heckel.ntfy.msg.DownloadManager
import io.heckel.ntfy.msg.DownloadType
import io.heckel.ntfy.msg.NotificationDispatcher
import io.heckel.ntfy.service.SubscriberService
import io.heckel.ntfy.service.SubscriberServiceManager
@ -125,9 +118,9 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
Log.addScrubTerm(s.topic)
}
// Update banner + WebSocket banner
// Update banner + JSON stream banner
showHideBatteryBanner(subscriptions)
showHideWebSocketBanner(subscriptions)
showHideJsonStreamBanner(subscriptions)
}
}
@ -175,25 +168,21 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
}
}
// WebSocket banner
val wsBanner = findViewById<View>(R.id.main_banner_websocket) // Banner visibility is toggled in onResume()
val wsText = findViewById<TextView>(R.id.main_banner_websocket_text)
val wsDismissButton = findViewById<Button>(R.id.main_banner_websocket_dontaskagain)
val wsRemindButton = findViewById<Button>(R.id.main_banner_websocket_remind_later)
val wsEnableButton = findViewById<Button>(R.id.main_banner_websocket_enable)
wsText.movementMethod = LinkMovementMethod.getInstance() // Make links clickable
wsDismissButton.setOnClickListener {
wsBanner.visibility = View.GONE
repository.setWebSocketRemindTime(Repository.WEBSOCKET_REMIND_TIME_NEVER)
// JSON stream banner
val jsonStreamBanner = findViewById<View>(R.id.main_banner_json_stream) // Banner visibility is toggled in onResume()
val jsonStreamDismissButton = findViewById<Button>(R.id.main_banner_json_stream_dontaskagain)
val jsonStreamRemindButton = findViewById<Button>(R.id.main_banner_json_stream_remind_later)
val jsonStreamLearnMoreButton = findViewById<Button>(R.id.main_banner_json_stream_learn_mode)
jsonStreamDismissButton.setOnClickListener {
jsonStreamBanner.visibility = View.GONE
repository.setJsonStreamRemindTime(Repository.JSON_STREAM_REMIND_TIME_NEVER)
}
wsRemindButton.setOnClickListener {
wsBanner.visibility = View.GONE
repository.setWebSocketRemindTime(System.currentTimeMillis() + ONE_DAY_MILLIS)
jsonStreamRemindButton.setOnClickListener {
jsonStreamBanner.visibility = View.GONE
repository.setJsonStreamRemindTime(System.currentTimeMillis() + ONE_DAY_MILLIS)
}
wsEnableButton.setOnClickListener {
repository.setConnectionProtocol(Repository.CONNECTION_PROTOCOL_WS)
SubscriberServiceManager(this).restart()
wsBanner.visibility = View.GONE
jsonStreamLearnMoreButton.setOnClickListener {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.main_banner_json_stream_button_learn_more_url))))
}
// Create notification channels right away, so we can configure them immediately after installing the app
@ -209,18 +198,6 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
schedulePeriodicPollWorker()
schedulePeriodicServiceRestartWorker()
schedulePeriodicDeleteWorker()
// Permissions
maybeRequestNotificationPermission()
}
private fun maybeRequestNotificationPermission() {
// Android 13 (SDK 33) requires that we ask for permission to post notifications
// https://developer.android.com/develop/ui/views/notifications/notification-permission
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.POST_NOTIFICATIONS), 0)
}
}
override fun onResume() {
@ -239,13 +216,13 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
Log.d(TAG, "Battery: ignoring optimizations = $ignoringOptimizations (we want this to be true); instant subscriptions = $hasInstantSubscriptions; remind time reached = $batteryRemindTimeReached; banner = $showBanner")
}
private fun showHideWebSocketBanner(subscriptions: List<Subscription>) {
val hasSelfHostedSubscriptions = subscriptions.count { it.baseUrl != appBaseUrl } > 0
private fun showHideJsonStreamBanner(subscriptions: List<Subscription>) {
val hasSelfhostedSubscriptions = subscriptions.count { it.baseUrl != appBaseUrl } > 0
val usingWebSockets = repository.getConnectionProtocol() == Repository.CONNECTION_PROTOCOL_WS
val wsRemindTimeReached = repository.getWebSocketRemindTime() < System.currentTimeMillis()
val showBanner = hasSelfHostedSubscriptions && wsRemindTimeReached && !usingWebSockets
val wsBanner = findViewById<View>(R.id.main_banner_websocket)
wsBanner.visibility = if (showBanner) View.VISIBLE else View.GONE
val jsonStreamRemindTimeReached = repository.getJsonStreamRemindTime() < System.currentTimeMillis()
val showBanner = hasSelfhostedSubscriptions && jsonStreamRemindTimeReached && !usingWebSockets
val jsonStreamBanner = findViewById<View>(R.id.main_banner_json_stream)
jsonStreamBanner.visibility = if (showBanner) View.VISIBLE else View.GONE
}
private fun schedulePeriodicPollWorker() {
@ -397,12 +374,10 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
}
true
}
R.id.main_menu_donate -> {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.main_menu_donate_url))))
true
}
R.id.main_menu_docs -> {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.main_menu_docs_url))))
//startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.main_menu_docs_url))))
val intent = Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS)
startActivity(intent)
true
}
else -> super.onOptionsItemSelected(item)
@ -446,20 +421,13 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
// Add subscription to database
val subscription = Subscription(
id = randomSubscriptionId(),
id = Random.nextLong(),
baseUrl = baseUrl,
topic = topic,
instant = instant,
dedicatedChannels = false,
mutedUntil = 0,
minPriority = Repository.MIN_PRIORITY_USE_GLOBAL,
autoDelete = Repository.AUTO_DELETE_USE_GLOBAL,
insistent = Repository.INSISTENT_MAX_PRIORITY_USE_GLOBAL,
lastNotificationId = null,
icon = null,
upAppId = null,
upConnectorToken = null,
displayName = null,
totalCount = 0,
newCount = 0,
lastActive = Date().time/1000
@ -477,12 +445,7 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
try {
val user = repository.getUser(subscription.baseUrl) // May be null
val notifications = api.poll(subscription.id, subscription.baseUrl, subscription.topic, user)
notifications.forEach { notification ->
repository.addNotification(notification)
if (notification.icon != null) {
DownloadManager.enqueue(this@MainActivity, notification.id, userAction = false, DownloadType.ICON)
}
}
notifications.forEach { notification -> repository.addNotification(notification) }
} catch (e: Exception) {
Log.e(TAG, "Unable to fetch notifications: ${e.message}", e)
}
@ -495,13 +458,21 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
private fun onSubscriptionItemClick(subscription: Subscription) {
if (actionMode != null) {
handleActionModeClick(subscription)
} else if (subscription.upAppId != null) { // UnifiedPush
startDetailSettingsView(subscription)
} else if (subscription.upAppId != null) { // Not UnifiedPush
displayUnifiedPushToast(subscription)
} else {
startDetailView(subscription)
}
}
private fun displayUnifiedPushToast(subscription: Subscription) {
runOnUiThread {
val appId = subscription.upAppId ?: return@runOnUiThread
val toastMessage = getString(R.string.main_unified_push_toast, appId)
Toast.makeText(this@MainActivity, toastMessage, Toast.LENGTH_LONG).show()
}
}
private fun onSubscriptionItemLongClick(subscription: Subscription) {
if (actionMode == null) {
beginActionMode(subscription)
@ -515,10 +486,9 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
var errorMessage = "" // First error
var newNotificationsCount = 0
repository.getSubscriptions().forEach { subscription ->
Log.d(TAG, "subscription: ${subscription}")
try {
val user = repository.getUser(subscription.baseUrl) // May be null
val notifications = api.poll(subscription.id, subscription.baseUrl, subscription.topic, user, subscription.lastNotificationId)
val notifications = api.poll(subscription.id, subscription.baseUrl, subscription.topic, user)
val newNotifications = repository.onlyNewNotifications(subscription.id, notifications)
newNotifications.forEach { notification ->
newNotificationsCount++
@ -528,7 +498,7 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
}
}
} catch (e: Exception) {
val topic = displayName(subscription)
val topic = topicShortUrl(subscription.baseUrl, subscription.topic)
if (errorMessage == "") errorMessage = "$topic: ${e.message}"
errors++
}
@ -555,30 +525,18 @@ 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)
}
private fun startDetailSettingsView(subscription: Subscription) {
Log.d(TAG, "Opening subscription settings for ${topicShortUrl(subscription.baseUrl, subscription.topic)}")
val intent = Intent(this, DetailSettingsActivity::class.java)
intent.putExtra(DetailActivity.EXTRA_SUBSCRIPTION_ID, subscription.id)
intent.putExtra(DetailActivity.EXTRA_SUBSCRIPTION_BASE_URL, subscription.baseUrl)
intent.putExtra(DetailActivity.EXTRA_SUBSCRIPTION_TOPIC, subscription.topic)
intent.putExtra(DetailActivity.EXTRA_SUBSCRIPTION_DISPLAY_NAME, displayName(subscription))
startActivity(intent)
}
private fun handleActionModeClick(subscription: Subscription) {
adapter.toggleSelection(subscription.id)
if (adapter.selected.size == 0) {
finishActionMode()
} else {
actionMode!!.title = adapter.selected.size.toString()
redrawList()
}
}
@ -622,7 +580,7 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
dialog.setOnShowListener {
dialog
.getButton(AlertDialog.BUTTON_POSITIVE)
.dangerButton(this)
.setTextAppearance(R.style.DangerText)
}
dialog.show()
}
@ -633,7 +591,8 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
private fun beginActionMode(subscription: Subscription) {
actionMode = startActionMode(this)
adapter.toggleSelection(subscription.id)
adapter.selected.add(subscription.id)
redrawList()
// Fade out FAB
fab.alpha = 1f
@ -686,7 +645,9 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
if (!this::mainList.isInitialized) {
return
}
adapter.notifyItemRangeChanged(0, adapter.currentList.size)
runOnUiThread {
mainList.adapter = adapter // Oh, what a hack ...
}
}
companion object {
@ -694,7 +655,6 @@ 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

@ -1,11 +1,9 @@
package io.heckel.ntfy.ui
import android.content.Context
import android.graphics.Color
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
@ -15,8 +13,7 @@ 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.util.displayName
import io.heckel.ntfy.util.readBitmapFromUriOrNull
import io.heckel.ntfy.util.topicShortUrl
import java.text.DateFormat
import java.util.*
@ -43,12 +40,6 @@ class MainAdapter(private val repository: Repository, private val onClick: (Subs
} else {
selected.add(subscriptionId)
}
if (selected.size != 0) {
val listIds = currentList.map { subscription -> subscription.id }
val subscriptionPosition = listIds.indexOf(subscriptionId)
notifyItemChanged(subscriptionPosition)
}
}
/* ViewHolder for Topic, takes in the inflated view and the onClick behavior. */
@ -56,7 +47,6 @@ class MainAdapter(private val repository: Repository, private val onClick: (Subs
RecyclerView.ViewHolder(itemView) {
private var subscription: Subscription? = null
private val context: Context = itemView.context
private val imageView: ImageView = itemView.findViewById(R.id.main_item_image)
private val nameView: TextView = itemView.findViewById(R.id.main_item_text)
private val statusView: TextView = itemView.findViewById(R.id.main_item_status)
private val dateView: TextView = itemView.findViewById(R.id.main_item_date)
@ -94,12 +84,7 @@ class MainAdapter(private val repository: Repository, private val onClick: (Subs
val globalMutedUntil = repository.getGlobalMutedUntil()
val showMutedForeverIcon = (subscription.mutedUntil == 1L || globalMutedUntil == 1L) && !isUnifiedPush
val showMutedUntilIcon = !showMutedForeverIcon && (subscription.mutedUntil > 1L || globalMutedUntil > 1L) && !isUnifiedPush
if (subscription.icon != null) {
imageView.setImageBitmap(subscription.icon.readBitmapFromUriOrNull(context))
} else {
imageView.setImageResource(R.drawable.ic_sms_gray_24dp)
}
nameView.text = displayName(subscription)
nameView.text = topicShortUrl(subscription.baseUrl, subscription.topic)
statusView.text = statusMessage
dateView.text = dateText
dateView.visibility = if (isUnifiedPush) View.GONE else View.VISIBLE
@ -116,8 +101,6 @@ class MainAdapter(private val repository: Repository, private val onClick: (Subs
itemView.setOnLongClickListener { onLongClick(subscription); true }
if (selected.contains(subscription.id)) {
itemView.setBackgroundResource(Colors.itemSelectedBackground(context))
} else {
itemView.setBackgroundColor(Color.TRANSPARENT)
}
}
}
@ -131,8 +114,4 @@ class MainAdapter(private val repository: Repository, private val onClick: (Subs
return oldItem == newItem
}
}
companion object {
const val TAG = "NtfyMainAdapter"
}
}

View file

@ -1,71 +0,0 @@
package io.heckel.ntfy.ui
import android.content.res.Configuration
import android.os.Build
import android.os.Bundle
import android.view.WindowInsetsController
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import io.heckel.ntfy.R
import io.heckel.ntfy.databinding.MainSettingsActivityBinding
class MainSettingsActivity : AppCompatActivity() {
private lateinit var mBinding: MainSettingsActivityBinding
@RequiresApi(Build.VERSION_CODES.R)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mBinding = MainSettingsActivityBinding.inflate(layoutInflater)
setContentView(mBinding.root)
setupToolbar()
setSystemBarsAppearance()
showPreferencesFragment()
}
private fun setupToolbar() {
mBinding.toolbar.setNavigationOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
}
@RequiresApi(Build.VERSION_CODES.R)
private fun setSystemBarsAppearance() {
val insetsController = window.insetsController ?: return
val isLightMode = isSystemInLightMode()
if (isLightMode) {
insetsController.setSystemBarsAppearance(
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
)
insetsController.setSystemBarsAppearance(
WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS,
WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS
)
} else {
insetsController.setSystemBarsAppearance(
0,
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
)
insetsController.setSystemBarsAppearance(
0,
WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS
)
}
}
private fun isSystemInLightMode(): Boolean {
val nightModeFlags = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
return nightModeFlags != Configuration.UI_MODE_NIGHT_YES
}
private fun showPreferencesFragment() {
supportFragmentManager
.beginTransaction()
.replace(R.id.fragment_container, PreferencesFragment())
.commit()
}
}

View file

@ -1,7 +1,6 @@
package io.heckel.ntfy.ui
import android.content.Context
import android.net.Uri
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
@ -10,6 +9,7 @@ import io.heckel.ntfy.db.*
import io.heckel.ntfy.up.Distributor
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlin.collections.List
class SubscriptionsViewModel(private val repository: Repository) : ViewModel() {
fun list(): LiveData<List<Subscription>> {
@ -32,14 +32,6 @@ class SubscriptionsViewModel(private val repository: Repository) : ViewModel() {
}
repository.removeAllNotifications(subscriptionId)
repository.removeSubscription(subscriptionId)
if (subscription.icon != null) {
val resolver = context.applicationContext.contentResolver
try {
resolver.delete(Uri.parse(subscription.icon), null, null)
} catch (_: Exception) {
// Don't care
}
}
}
suspend fun get(baseUrl: String, topic: String): Subscription? {
@ -49,7 +41,7 @@ class SubscriptionsViewModel(private val repository: Repository) : ViewModel() {
class SubscriptionsViewModelFactory(private val repository: Repository) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T =
override fun <T : ViewModel?> create(modelClass: Class<T>) =
with(modelClass){
when {
isAssignableFrom(SubscriptionsViewModel::class.java) -> SubscriptionsViewModel(repository) as T

View file

@ -8,6 +8,7 @@ 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

View file

@ -1,37 +0,0 @@
package io.heckel.ntfy.ui
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.widget.Toolbar
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreferenceCompat
import io.heckel.ntfy.R
import io.heckel.ntfy.service.SubscriberService
import io.heckel.ntfy.util.Log
class PreferencesFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.settings_preferences, rootKey)
val preference: SwitchPreferenceCompat? =
findPreference(getString(R.string.eos_preference_key_is_enabled))
preference?.setOnPreferenceChangeListener { _, newValue ->
val isChecked = newValue as Boolean
val intent = Intent(context, SubscriberService::class.java)
intent.action = if (isChecked) {
SubscriberService.Action.START.name
} else {
SubscriberService.Action.STOP.name
}
requireContext().startService(intent)
true
}
}
}

View file

@ -2,14 +2,13 @@ package io.heckel.ntfy.ui
import android.Manifest
import android.app.AlertDialog
import android.app.NotificationManager
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.text.TextUtils
import android.widget.Button
import android.widget.Toast
@ -85,7 +84,7 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
// Save current activity title, so we can set it again after a configuration change
// Save current activity title so we can set it again after a configuration change
outState.putCharSequence(TITLE_TAG, title)
}
@ -122,6 +121,7 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
class SettingsFragment : PreferenceFragmentCompat() {
private lateinit var repository: Repository
private lateinit var serviceManager: SubscriberServiceManager
private lateinit var notificationManager: NotificationManager
private var autoDownloadSelection = AUTO_DOWNLOAD_SELECTION_NOT_SET
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
@ -131,6 +131,7 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
repository = Repository.getInstance(requireActivity())
serviceManager = SubscriberServiceManager(requireActivity())
autoDownloadSelection = repository.getAutoDownloadMaxSize() // Only used for <= Android P, due to permissions request
notificationManager = requireContext().getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// Important note: We do not use the default shared prefs to store settings. Every
// preferenceDataStore is overridden to use the repository. This is convenient, because
@ -165,8 +166,9 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
return repository.getGlobalMutedUntil().toString()
}
}
mutedUntil?.summaryProvider = Preference.SummaryProvider<ListPreference> {
when (val mutedUntilValue = repository.getGlobalMutedUntil()) {
mutedUntil?.summaryProvider = Preference.SummaryProvider<ListPreference> { _ ->
val mutedUntilValue = repository.getGlobalMutedUntil()
when (mutedUntilValue) {
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 -> {
@ -190,9 +192,10 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
}
}
minPriority?.summaryProvider = Preference.SummaryProvider<ListPreference> { pref ->
when (val minPriorityValue = pref.value.toIntOrNull() ?: 1) { // 1/low means all priorities
PRIORITY_MIN -> getString(R.string.settings_notifications_min_priority_summary_any)
PRIORITY_MAX -> getString(R.string.settings_notifications_min_priority_summary_max)
val minPriorityValue = pref.value.toIntOrNull() ?: 1 // 1/low means all priorities
when (minPriorityValue) {
1 -> getString(R.string.settings_notifications_min_priority_summary_any)
5 -> getString(R.string.settings_notifications_min_priority_summary_max)
else -> {
val minPriorityString = toPriorityString(requireContext(), minPriorityValue)
getString(R.string.settings_notifications_min_priority_summary_x_or_higher, minPriorityValue, minPriorityString)
@ -200,40 +203,33 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
}
}
// Keep alerting for max priority
val insistentMaxPriorityPrefId = context?.getString(R.string.settings_notifications_insistent_max_priority_key) ?: return
val insistentMaxPriority: SwitchPreference? = findPreference(insistentMaxPriorityPrefId)
insistentMaxPriority?.isChecked = repository.getInsistentMaxPriorityEnabled()
insistentMaxPriority?.preferenceDataStore = object : PreferenceDataStore() {
override fun putBoolean(key: String?, value: Boolean) {
repository.setInsistentMaxPriorityEnabled(value)
// DND override priority
val dndOverrideEnabled = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && notificationManager.isNotificationPolicyAccessGranted
val dndOverridePriorityPrefId = context?.getString(R.string.settings_notifications_dnd_override_priority_key) ?: return
val dndOverridePriority: ListPreference? = findPreference(minPriorityPrefId)
dndOverridePriority?.isVisible = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
dndOverridePriority?.value = repository.getDnsOverridePriority().toString()
dndOverridePriority?.preferenceDataStore = object : PreferenceDataStore() {
override fun putString(key: String?, value: String?) {
val dndOverridePriorityValue = value?.toIntOrNull() ?:return
//repository.setMinPriority(minPriorityValue)
}
override fun getBoolean(key: String?, defValue: Boolean): Boolean {
return repository.getInsistentMaxPriorityEnabled()
override fun getString(key: String?, defValue: String?): String {
return repository.getDnsOverridePriority().toString()
}
}
insistentMaxPriority?.summaryProvider = Preference.SummaryProvider<SwitchPreference> { pref ->
if (pref.isChecked) {
getString(R.string.settings_notifications_insistent_max_priority_summary_enabled)
} else {
getString(R.string.settings_notifications_insistent_max_priority_summary_disabled)
dndOverridePriority?.summaryProvider = Preference.SummaryProvider<ListPreference> { pref ->
val priorityValue = pref.value.toIntOrNull() ?: 1 // 1/low means all priorities
when (priorityValue) {
1 -> getString(R.string.settings_notifications_min_priority_summary_any)
5 -> getString(R.string.settings_notifications_min_priority_summary_max)
else -> {
val minPriorityString = toPriorityString(requireContext(), priorityValue)
getString(R.string.settings_notifications_min_priority_summary_x_or_higher, priorityValue, minPriorityString)
}
}
}
// Channel settings
val channelPrefsPrefId = context?.getString(R.string.settings_notifications_channel_prefs_key) ?: return
val channelPrefs: Preference? = findPreference(channelPrefsPrefId)
channelPrefs?.isVisible = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
channelPrefs?.preferenceDataStore = object : PreferenceDataStore() { } // Dummy store to protect from accidentally overwriting
channelPrefs?.onPreferenceClickListener = OnPreferenceClickListener {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startActivity(Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply {
putExtra(Settings.EXTRA_APP_PACKAGE, BuildConfig.APPLICATION_ID)
})
}
false
}
// Auto download
val autoDownloadPrefId = context?.getString(R.string.settings_notifications_auto_download_key) ?: return
val autoDownload: ListPreference? = findPreference(autoDownloadPrefId)
@ -248,7 +244,8 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
}
}
autoDownload?.summaryProvider = Preference.SummaryProvider<ListPreference> { pref ->
when (val maxSize = pref.value.toLongOrNull() ?: repository.getAutoDownloadMaxSize()) {
val maxSize = pref.value.toLongOrNull() ?: repository.getAutoDownloadMaxSize()
when (maxSize) {
Repository.AUTO_DOWNLOAD_NEVER -> getString(R.string.settings_notifications_auto_download_summary_never)
Repository.AUTO_DOWNLOAD_ALWAYS -> getString(R.string.settings_notifications_auto_download_summary_always)
else -> getString(R.string.settings_notifications_auto_download_summary_smaller_than_x, formatBytes(maxSize, decimals = 0))
@ -280,7 +277,8 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
}
}
autoDelete?.summaryProvider = Preference.SummaryProvider<ListPreference> { pref ->
when (pref.value.toLongOrNull() ?: repository.getAutoDeleteSeconds()) {
val seconds = pref.value.toLongOrNull() ?: repository.getAutoDeleteSeconds()
when (seconds) {
Repository.AUTO_DELETE_NEVER -> getString(R.string.settings_notifications_auto_delete_summary_never)
Repository.AUTO_DELETE_ONE_DAY_SECONDS -> getString(R.string.settings_notifications_auto_delete_summary_one_day)
Repository.AUTO_DELETE_THREE_DAYS_SECONDS -> getString(R.string.settings_notifications_auto_delete_summary_three_days)
@ -364,26 +362,6 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
}
}
// Enable UnifiedPush
val unifiedPushEnabledPrefId = context?.getString(R.string.settings_advanced_unifiedpush_key) ?: return
val unifiedPushEnabled: SwitchPreference? = findPreference(unifiedPushEnabledPrefId)
unifiedPushEnabled?.isChecked = repository.getUnifiedPushEnabled()
unifiedPushEnabled?.preferenceDataStore = object : PreferenceDataStore() {
override fun putBoolean(key: String?, value: Boolean) {
repository.setUnifiedPushEnabled(value)
}
override fun getBoolean(key: String?, defValue: Boolean): Boolean {
return repository.getUnifiedPushEnabled()
}
}
unifiedPushEnabled?.summaryProvider = Preference.SummaryProvider<SwitchPreference> { pref ->
if (pref.isChecked) {
getString(R.string.settings_advanced_unifiedpush_summary_enabled)
} else {
getString(R.string.settings_advanced_unifiedpush_summary_disabled)
}
}
// Export logs
val exportLogsPrefId = context?.getString(R.string.settings_advanced_export_logs_key) ?: return
val exportLogs: ListPreference? = findPreference(exportLogsPrefId)
@ -431,7 +409,7 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
getString(R.string.settings_advanced_record_logs_summary_disabled)
}
}
recordLogsEnabled?.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, _ ->
recordLogsEnabled?.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, v ->
lifecycleScope.launch(Dispatchers.IO) {
repository.getSubscriptions().forEach { s ->
Log.addScrubTerm(shortUrl(s.baseUrl), Log.TermType.Domain)
@ -476,7 +454,7 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
backup?.preferenceDataStore = object : PreferenceDataStore() { } // Dummy store to protect from accidentally overwriting
backup?.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, v ->
backupSelection = v.toString()
val timestamp = SimpleDateFormat("yyMMdd-HHmm").format(Date())
val timestamp = SimpleDateFormat("yyMMdd-HHmm").format(Date());
val suggestedFilename = when (backupSelection) {
BACKUP_EVERYTHING_NO_USERS -> "ntfy-backup-no-users-$timestamp.json"
BACKUP_SETTINGS_ONLY -> "ntfy-settings-$timestamp.json"
@ -517,10 +495,7 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
}
}
restore?.onPreferenceClickListener = OnPreferenceClickListener {
// Overly open mime type filter (because of https://github.com/binwiederhier/ntfy/issues/223).
// This filter could likely be stricter if we'd write the mime type properly in Backuper.backup(),
// but just in case we want to restore from a file we didn't write outselves, we'll keep this "*/*".
restoreResultLauncher.launch("*/*")
restoreResultLauncher.launch(Backuper.MIME_TYPE)
true
}
@ -623,9 +598,10 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
throw Exception("Unexpected response ${response.code}")
}
val body = response.body?.string()?.trim()
if (body.isNullOrEmpty()) throw Exception("Return body is empty")
if (body == null || body.isEmpty()) throw Exception("Return body is empty")
Log.d(TAG, "Logs uploaded successfully: $body")
val resp = gson.fromJson(body.toString(), NopasteResponse::class.java)
val context = context ?: return@launch
requireActivity().runOnUiThread {
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("logs URL", resp.url)
@ -641,6 +617,7 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
}
} catch (e: Exception) {
Log.w(TAG, "Error uploading logs", e)
val context = context ?: return@launch
requireActivity().runOnUiThread {
Toast
.makeText(context, getString(R.string.settings_advanced_export_logs_error_uploading, e.message), Toast.LENGTH_LONG)

View file

@ -1,6 +1,7 @@
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
@ -192,7 +193,10 @@ class ShareActivity : AppCompatActivity() {
return
}
try {
contentImage.setImageBitmap(fileUri!!.readBitmapFromUri(applicationContext))
val resolver = applicationContext.contentResolver
val bitmapStream = resolver.openInputStream(fileUri!!)
val bitmap = BitmapFactory.decodeStream(bitmapStream)
contentImage.setImageBitmap(bitmap)
contentText.text = getString(R.string.share_content_image_text)
show(image = true)
} catch (e: Exception) {
@ -294,7 +298,7 @@ class ShareActivity : AppCompatActivity() {
.show()
}
} catch (e: Exception) {
val errorMessage = if (e is ApiService.UnauthorizedException) {
val message = if (e is ApiService.UnauthorizedException) {
if (e.user != null) {
getString(R.string.detail_test_message_error_unauthorized_user, e.user.username)
} else {
@ -307,7 +311,7 @@ class ShareActivity : AppCompatActivity() {
}
runOnUiThread {
progress.visibility = View.GONE
errorText.text = errorMessage
errorText.text = message
errorImage.visibility = View.VISIBLE
errorText.visibility = View.VISIBLE
}
@ -325,7 +329,7 @@ class ShareActivity : AppCompatActivity() {
contentText.text.isNotEmpty() && topicText.text.isNotEmpty()
}
sendItem.isEnabled = enabled
sendItem.icon?.alpha = if (enabled) 255 else 130
sendItem.icon.alpha = if (enabled) 255 else 130
}
private fun getBaseUrl(): String {

View file

@ -3,17 +3,19 @@ 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.text.Editable
import android.text.TextWatcher
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
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() {
@ -96,14 +98,28 @@ class UserFragment : DialogFragment() {
// Delete button should be red
if (user != null) {
dialog
.getButton(AlertDialog.BUTTON_NEUTRAL)
.dangerButton(requireContext())
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())))
}
}
// Validate input when typing
val textWatcher = AfterChangedTextWatcher {
validateInput()
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
}
}
baseUrlView.addTextChangedListener(textWatcher)
usernameView.addTextChangedListener(textWatcher)
@ -124,7 +140,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
}

View file

@ -4,16 +4,16 @@ import android.content.Context
import android.content.Intent
import io.heckel.ntfy.R
import io.heckel.ntfy.app.Application
import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.db.Subscription
import io.heckel.ntfy.service.SubscriberServiceManager
import io.heckel.ntfy.util.*
import io.heckel.ntfy.util.Log
import io.heckel.ntfy.util.randomString
import io.heckel.ntfy.util.topicUrlUp
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
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.
@ -38,73 +38,52 @@ class BroadcastReceiver : android.content.BroadcastReceiver() {
val repository = app.repository
val distributor = Distributor(app)
Log.d(TAG, "REGISTER received for app $appId (connectorToken=$connectorToken)")
if (!repository.getUnifiedPushEnabled()) {
Log.w(TAG, "Refusing registration because 'EnableUP' is disabled")
distributor.sendRegistrationFailed(appId, connectorToken, "UnifiedPush is disabled in ntfy")
return
}
if (appId.isBlank()) {
Log.w(TAG, "Refusing registration: Empty application")
distributor.sendRegistrationFailed(appId, connectorToken, "Empty application string")
return
}
GlobalScope.launch(Dispatchers.IO) {
// We're doing all of this inside a critical section, because of possible races.
// See https://github.com/binwiederhier/ntfy/issues/230 for details.
mutex.withLock {
val existingSubscription = repository.getSubscriptionByConnectorToken(connectorToken)
if (existingSubscription != null) {
if (existingSubscription.upAppId == appId) {
val endpoint = topicUrlUp(existingSubscription.baseUrl, existingSubscription.topic)
Log.d(TAG, "Subscription with connectorToken $connectorToken exists. Sending endpoint $endpoint.")
distributor.sendEndpoint(appId, connectorToken, endpoint)
} else {
Log.d(TAG, "Subscription with connectorToken $connectorToken exists for a different app. Refusing registration.")
distributor.sendRegistrationFailed(appId, connectorToken, "Connector token already exists")
}
return@launch
}
// Add subscription
val baseUrl = repository.getDefaultBaseUrl() ?: context.getString(R.string.app_base_url)
val topic = UP_PREFIX + randomString(TOPIC_RANDOM_ID_LENGTH)
val endpoint = topicUrlUp(baseUrl, topic)
val subscription = Subscription(
id = randomSubscriptionId(),
baseUrl = baseUrl,
topic = topic,
instant = true, // No Firebase, always instant!
dedicatedChannels = false,
mutedUntil = 0,
minPriority = Repository.MIN_PRIORITY_USE_GLOBAL,
autoDelete = Repository.AUTO_DELETE_USE_GLOBAL,
insistent = Repository.INSISTENT_MAX_PRIORITY_USE_GLOBAL,
lastNotificationId = null,
icon = null,
upAppId = appId,
upConnectorToken = connectorToken,
displayName = null,
totalCount = 0,
newCount = 0,
lastActive = Date().time/1000
)
Log.d(TAG, "Adding subscription with for app $appId (connectorToken $connectorToken): $subscription")
try {
// Note, this may fail due to a SQL constraint exception, see https://github.com/binwiederhier/ntfy/issues/185
repository.addSubscription(subscription)
val existingSubscription = repository.getSubscriptionByConnectorToken(connectorToken)
if (existingSubscription != null) {
if (existingSubscription.upAppId == appId) {
val endpoint = topicUrlUp(existingSubscription.baseUrl, existingSubscription.topic)
Log.d(TAG, "Subscription with connectorToken $connectorToken exists. Sending endpoint $endpoint.")
distributor.sendEndpoint(appId, connectorToken, endpoint)
// Refresh (and maybe start) foreground service
SubscriberServiceManager.refresh(app)
} catch (e: Exception) {
Log.w(TAG, "Failed to add subscription", e)
distributor.sendRegistrationFailed(appId, connectorToken, e.message)
} else {
Log.d(TAG, "Subscription with connectorToken $connectorToken exists for a different app. Refusing registration.")
distributor.sendRegistrationFailed(appId, connectorToken, "Connector token already exists")
}
return@launch
}
// Add to log scrubber
Log.addScrubTerm(shortUrl(baseUrl), Log.TermType.Domain)
Log.addScrubTerm(topic)
// Add subscription
val baseUrl = repository.getDefaultBaseUrl() ?: context.getString(R.string.app_base_url)
val topic = UP_PREFIX + randomString(TOPIC_RANDOM_ID_LENGTH)
val endpoint = topicUrlUp(baseUrl, topic)
val subscription = Subscription(
id = Random.nextLong(),
baseUrl = baseUrl,
topic = topic,
instant = true, // No Firebase, always instant!
mutedUntil = 0,
upAppId = appId,
upConnectorToken = connectorToken,
totalCount = 0,
newCount = 0,
lastActive = Date().time/1000
)
Log.d(TAG, "Adding subscription with for app $appId (connectorToken $connectorToken): $subscription")
try {
// Note, this may fail due to a SQL constraint exception, see https://github.com/binwiederhier/ntfy/issues/185
repository.addSubscription(subscription)
distributor.sendEndpoint(appId, connectorToken, endpoint)
// Refresh (and maybe start) foreground service
SubscriberServiceManager.refresh(app)
} catch (e: Exception) {
Log.w(TAG, "Failed to add subscription", e)
distributor.sendRegistrationFailed(appId, connectorToken, e.message)
}
}
}
@ -116,24 +95,19 @@ class BroadcastReceiver : android.content.BroadcastReceiver() {
val distributor = Distributor(app)
Log.d(TAG, "UNREGISTER received (connectorToken=$connectorToken)")
GlobalScope.launch(Dispatchers.IO) {
// We're doing all of this inside a critical section, because of possible races.
// See https://github.com/binwiederhier/ntfy/issues/230 for details.
mutex.withLock {
val existingSubscription = repository.getSubscriptionByConnectorToken(connectorToken)
if (existingSubscription == null) {
Log.d(TAG, "Subscription with connectorToken $connectorToken does not exist. Ignoring.")
return@launch
}
// Remove subscription
Log.d(TAG, "Removing subscription ${existingSubscription.id} with connectorToken $connectorToken")
repository.removeSubscription(existingSubscription.id)
existingSubscription.upAppId?.let { appId -> distributor.sendUnregistered(appId, connectorToken) }
// Refresh (and maybe stop) foreground service
SubscriberServiceManager.refresh(context)
val existingSubscription = repository.getSubscriptionByConnectorToken(connectorToken)
if (existingSubscription == null) {
Log.d(TAG, "Subscription with connectorToken $connectorToken does not exist. Ignoring.")
return@launch
}
// Remove subscription
Log.d(TAG, "Removing subscription ${existingSubscription.id} with connectorToken $connectorToken")
repository.removeSubscription(existingSubscription.id)
existingSubscription.upAppId?.let { appId -> distributor.sendUnregistered(appId, connectorToken) }
// Refresh (and maybe stop) foreground service
SubscriberServiceManager.refresh(context)
}
}
@ -141,7 +115,5 @@ class BroadcastReceiver : android.content.BroadcastReceiver() {
private const val TAG = "NtfyUpBroadcastRecv"
private const val UP_PREFIX = "up"
private const val TOPIC_RANDOM_ID_LENGTH = 12
val mutex = Mutex() // https://github.com/binwiederhier/ntfy/issues/230
}
}

View file

@ -10,7 +10,7 @@ import io.heckel.ntfy.util.Log
*/
class Distributor(val context: Context) {
fun sendMessage(app: String, connectorToken: String, message: ByteArray) {
Log.d(TAG, "Sending MESSAGE to $app (token=$connectorToken): ${message.size} bytes")
Log.d(TAG, "Sending MESSAGE to $app (token=$connectorToken): ${String(message)} (${message.size} bytes)}")
val broadcastIntent = Intent()
broadcastIntent.`package` = app
broadcastIntent.action = ACTION_MESSAGE

View file

@ -1,11 +0,0 @@
package io.heckel.ntfy.util
const val ANDROID_APP_MIME_TYPE = "application/vnd.android.package-archive"
const val PRIORITY_MIN = 1
const val PRIORITY_LOW = 2
const val PRIORITY_DEFAULT = 3
const val PRIORITY_HIGH = 4
const val PRIORITY_MAX = 5
val ALL_PRIORITIES = listOf(PRIORITY_MIN, PRIORITY_LOW, PRIORITY_DEFAULT, PRIORITY_HIGH, PRIORITY_MAX)

View file

@ -9,9 +9,6 @@ import android.content.Context
import android.content.res.Configuration
import android.content.res.Configuration.UI_MODE_NIGHT_YES
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.drawable.RippleDrawable
import android.net.Uri
import android.os.Build
import android.os.PowerManager
@ -22,20 +19,14 @@ 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.db.Notification
import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.db.Subscription
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
import kotlinx.coroutines.launch
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
@ -44,13 +35,11 @@ import okio.source
import java.io.File
import java.io.FileNotFoundException
import java.io.IOException
import java.security.MessageDigest
import java.security.SecureRandom
import java.text.DateFormat
import java.text.StringCharacterIterator
import java.util.*
import kotlin.math.abs
import kotlin.math.absoluteValue
fun topicUrl(baseUrl: String, topic: String) = "${baseUrl}/${topic}"
fun topicUrlUp(baseUrl: String, topic: String) = "${baseUrl}/${topic}?up=1" // UnifiedPush
@ -60,14 +49,6 @@ 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 subscriptionTopicShortUrl(subscription: Subscription) : String {
return topicShortUrl(subscription.baseUrl, subscription.topic)
}
fun displayName(subscription: Subscription) : String {
return subscription.displayName ?: subscriptionTopicShortUrl(subscription)
}
fun shortUrl(url: String) = url
.replace("http://", "")
.replace("https://", "")
@ -99,16 +80,17 @@ fun formatDateShort(timestampSecs: Long): String {
}
fun toPriority(priority: Int?): Int {
return if (priority != null && ALL_PRIORITIES.contains(priority)) priority else PRIORITY_DEFAULT
if (priority != null && (1..5).contains(priority)) return priority
else return 3
}
fun toPriorityString(context: Context, priority: Int): String {
return when (priority) {
PRIORITY_MIN -> context.getString(R.string.settings_notifications_priority_min)
PRIORITY_LOW -> context.getString(R.string.settings_notifications_priority_low)
PRIORITY_DEFAULT -> context.getString(R.string.settings_notifications_priority_default)
PRIORITY_HIGH -> context.getString(R.string.settings_notifications_priority_high)
PRIORITY_MAX -> context.getString(R.string.settings_notifications_priority_max)
1 -> context.getString(R.string.settings_notifications_priority_min)
2 -> context.getString(R.string.settings_notifications_priority_low)
3 -> context.getString(R.string.settings_notifications_priority_default)
4 -> context.getString(R.string.settings_notifications_priority_high)
5 -> context.getString(R.string.settings_notifications_priority_max)
else -> context.getString(R.string.settings_notifications_priority_default)
}
}
@ -190,7 +172,7 @@ fun formatTitle(subscription: Subscription, notification: Notification): String
return if (notification.title != "") {
formatTitle(notification)
} else {
displayName(subscription)
topicShortUrl(subscription.baseUrl, subscription.topic)
}
}
@ -203,24 +185,13 @@ fun formatTitle(notification: Notification): String {
}
}
fun formatActionLabel(action: Action): String {
return when (action.progress) {
ACTION_PROGRESS_ONGOING -> action.label + ""
ACTION_PROGRESS_SUCCESS -> action.label + " ✔️"
ACTION_PROGRESS_FAILED -> action.label + " ❌️"
else -> action.label
}
}
fun maybeAppendActionErrors(message: String, notification: Notification): String {
val actionErrors = notification.actions
.orEmpty()
.mapNotNull { action -> action.error }
.joinToString("\n")
if (actionErrors.isEmpty()) {
return message
} else {
return "${message}\n\n${actionErrors}"
// 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
}
}
@ -259,14 +230,6 @@ fun fileStat(context: Context, contentUri: Uri?): FileInfo {
}
}
fun maybeFileStat(context: Context, contentUri: String?): FileInfo? {
return try {
fileStat(context, Uri.parse(contentUri)) // Throws if the file does not exist
} catch (_: Exception) {
null
}
}
data class FileInfo(
val filename: String,
val size: Long,
@ -289,13 +252,6 @@ fun randomString(len: Int): String {
return (1..len).map { chars[random.nextInt(chars.size)] }.joinToString("")
}
// Generates a random, positive subscription ID between 0-10M. This ensures that it doesn't have issues
// when exported to JSON. It uses SecureRandom, because Random causes issues in the emulator (generating the
// same value again and again), sometimes.
fun randomSubscriptionId(): Long {
return SecureRandom().nextLong().absoluteValue % 100_000_000
}
// Allows letting multiple variables at once, see https://stackoverflow.com/a/35522422/1440785
inline fun <T1: Any, T2: Any, R: Any> safeLet(p1: T1?, p2: T2?, block: (T1, T2)->R?): R? {
return if (p1 != null && p2 != null) block(p1, p2) else null
@ -325,7 +281,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 == ANDROID_APP_MIME_TYPE) {
} else if (mimeType == "application/vnd.android.package-archive") {
R.drawable.ic_file_app_gray_24dp
} else {
R.drawable.ic_file_document_blue_24dp
@ -336,15 +292,6 @@ 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 == ANDROID_APP_MIME_TYPE && !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
@ -402,53 +349,6 @@ fun View.makeEndIconSmaller(resources: Resources) {
requestLayout()
}
// Shows the ripple effect on the view, if it is ripple-able, see https://stackoverflow.com/a/56314062/1440785
fun View.showRipple() {
if (background is RippleDrawable) {
background.state = intArrayOf(android.R.attr.state_pressed, android.R.attr.state_enabled)
}
}
// Hides the ripple effect on the view, if it is ripple-able, see https://stackoverflow.com/a/56314062/1440785
fun View.hideRipple() {
if (background is RippleDrawable) {
background.state = intArrayOf()
}
}
// Toggles the ripple effect on the view, if it is ripple-able
fun View.ripple(scope: CoroutineScope) {
showRipple()
scope.launch(Dispatchers.Main) {
delay(200)
hideRipple()
}
}
fun Uri.readBitmapFromUri(context: Context): Bitmap {
val resolver = context.applicationContext.contentResolver
val bitmapStream = resolver.openInputStream(this)
val bitmap = BitmapFactory.decodeStream(bitmapStream)
if (bitmap.byteCount > 100 * 1024 * 1024) {
// If the Bitmap is too large to be rendered (100 MB), it will throw a RuntimeException downstream.
// This workaround throws a catchable exception instead. See issue #474. From https://stackoverflow.com/a/53334563/1440785
throw Exception("Bitmap too large to draw on Canvas (${bitmap.byteCount} bytes)")
}
return bitmap
}
fun String.readBitmapFromUri(context: Context): Bitmap {
return Uri.parse(this).readBitmapFromUri(context)
}
fun String.readBitmapFromUriOrNull(context: Context): Bitmap? {
return try {
this.readBitmapFromUri(context)
} catch (_: Exception) {
null
}
}
// TextWatcher that only implements the afterTextChanged method
class AfterChangedTextWatcher(val afterTextChangedFn: (s: Editable?) -> Unit) : TextWatcher {
override fun afterTextChanged(s: Editable?) {
@ -483,29 +383,11 @@ fun ensureSafeNewFile(dir: File, name: String): File {
fun copyToClipboard(context: Context, notification: Notification) {
val message = decodeMessage(notification)
val text = message + "\n\n" + formatDateShort(notification.timestamp)
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("notification message", message)
val clip = ClipData.newPlainText("notification message", text)
clipboard.setPrimaryClip(clip)
Toast
.makeText(context, context.getString(R.string.detail_copied_to_clipboard_message), Toast.LENGTH_LONG)
.show()
}
fun String.sha256(): String {
val md = MessageDigest.getInstance("SHA-256")
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)))
}
}
fun Long.nullIfZero(): Long? {
return if (this == 0L) return null else this
}

View file

@ -2,19 +2,15 @@ package io.heckel.ntfy.work
import android.content.Context
import android.net.Uri
import androidx.core.content.FileProvider
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import io.heckel.ntfy.BuildConfig
import io.heckel.ntfy.db.ATTACHMENT_PROGRESS_DELETED
import io.heckel.ntfy.db.PROGRESS_DELETED
import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.msg.DownloadIconWorker
import io.heckel.ntfy.ui.DetailAdapter
import io.heckel.ntfy.util.Log
import io.heckel.ntfy.util.maybeFileStat
import io.heckel.ntfy.util.topicShortUrl
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File
/**
* Deletes notifications marked for deletion and attachments for deleted notifications.
@ -30,23 +26,8 @@ class DeleteWorker(ctx: Context, params: WorkerParameters) : CoroutineWorker(ctx
override suspend fun doWork(): Result {
return withContext(Dispatchers.IO) {
// Run "expired icons" and "expired attachments" before notifications,
// so we will also catch manually deleted notifications
try {
deleteExpiredIcons()
} catch (e: Exception) {
Log.w(TAG, "Failed to delete expired icons", e)
}
try {
deleteExpiredAttachments()
} catch (e: Exception) {
Log.w(TAG, "Failed to delete expired attachments", e)
}
try {
deleteExpiredNotifications()
} catch (e: Exception) {
Log.w(TAG, "Failed to delete expired notifications", e)
}
deleteExpiredAttachments() // Before notifications, so we will also catch manually deleted notifications
deleteExpiredNotifications()
return@withContext Result.success()
}
}
@ -67,68 +48,34 @@ class DeleteWorker(ctx: Context, params: WorkerParameters) : CoroutineWorker(ctx
}
val newAttachment = attachment.copy(
contentUri = null,
progress = ATTACHMENT_PROGRESS_DELETED
progress = PROGRESS_DELETED
)
val newNotification = notification.copy(attachment = newAttachment)
repository.updateNotification(newNotification)
} catch (e: Exception) {
Log.w(TAG, "Failed to delete attachment for notification: ${e.message}", e)
Log.w(DetailAdapter.TAG, "Failed to delete attachment for notification: ${e.message}", e)
}
}
}
private fun deleteExpiredIcons() {
Log.d(TAG, "Deleting icons for deleted notifications")
val repository = Repository.getInstance(applicationContext)
val activeIconUris = repository.getActiveIconUris()
val activeIconFilenames = activeIconUris
.mapNotNull { maybeFileStat(applicationContext, it)?.filename }
.toSet()
val iconDir = File(applicationContext.cacheDir, DownloadIconWorker.ICON_CACHE_DIR)
val allIconFilenames = iconDir.listFiles()?.map{ file -> file.name }.orEmpty()
val filenamesToDelete = allIconFilenames.minus(activeIconFilenames)
filenamesToDelete.forEach { filename ->
try {
val file = File(iconDir, filename)
val deleted = file.delete()
if (!deleted) {
Log.w(TAG, "Unable to delete icon: $filename")
}
val uri = FileProvider.getUriForFile(applicationContext,
DownloadIconWorker.FILE_PROVIDER_AUTHORITY, file).toString()
repository.clearIconUri(uri)
} catch (e: Exception) {
Log.w(TAG, "Failed to delete icon: ${e.message}", e)
}
}
}
private suspend fun deleteExpiredNotifications() {
private fun deleteExpiredNotifications() {
Log.d(TAG, "Deleting expired notifications")
val repository = Repository.getInstance(applicationContext)
val subscriptions = repository.getSubscriptions()
subscriptions.forEach { subscription ->
val logId = topicShortUrl(subscription.baseUrl, subscription.topic)
val deleteAfterSeconds = if (subscription.autoDelete == Repository.AUTO_DELETE_USE_GLOBAL) {
repository.getAutoDeleteSeconds()
} else {
subscription.autoDelete
}
if (deleteAfterSeconds == Repository.AUTO_DELETE_NEVER) {
Log.d(TAG, "[$logId] Not deleting any notifications; global setting set to NEVER")
return@forEach
}
// Mark as deleted
val markDeletedOlderThanTimestamp = (System.currentTimeMillis()/1000) - deleteAfterSeconds
Log.d(TAG, "[$logId] Marking notifications older than $markDeletedOlderThanTimestamp as deleted")
repository.markAsDeletedIfOlderThan(subscription.id, markDeletedOlderThanTimestamp)
// Hard delete
val deleteOlderThanTimestamp = (System.currentTimeMillis()/1000) - HARD_DELETE_AFTER_SECONDS
Log.d(TAG, "[$logId] Hard deleting notifications older than $markDeletedOlderThanTimestamp")
repository.removeNotificationsIfOlderThan(subscription.id, deleteOlderThanTimestamp)
val deleteAfterSeconds = repository.getAutoDeleteSeconds()
if (deleteAfterSeconds == Repository.AUTO_DELETE_NEVER) {
Log.d(TAG, "Not deleting any notifications; global setting set to NEVER")
return
}
// Mark as deleted
val markDeletedOlderThanTimestamp = (System.currentTimeMillis()/1000) - deleteAfterSeconds
Log.d(TAG, "Marking notifications older than $markDeletedOlderThanTimestamp as deleted")
repository.markAsDeletedIfOlderThan(markDeletedOlderThanTimestamp)
// Hard delete
val deleteOlderThanTimestamp = (System.currentTimeMillis()/1000) - HARD_DELETE_AFTER_SECONDS
Log.d(TAG, "Hard deleting notifications older than $markDeletedOlderThanTimestamp")
repository.removeNotificationsIfOlderThan(deleteOlderThanTimestamp)
}
companion object {

View file

@ -45,7 +45,7 @@ class PollWorker(ctx: Context, params: WorkerParameters) : CoroutineWorker(ctx,
baseUrl = subscription.baseUrl,
topic = subscription.topic,
user = user,
since = subscription.lastNotificationId
since = subscription.lastActive
)
val newNotifications = repository
.onlyNewNotifications(subscription.id, notifications)

View file

@ -1,31 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="50dp"
android:height="50dp"
android:viewportWidth="50"
android:viewportHeight="50">
<path
android:pathData="m7.8399,6.35c-3.58,0 -6.6469,2.817 -6.6469,6.3983v0.003l0.0351,27.8668 -0.8991,6.6347 12.2261,-3.248L42.9487,44.0049c3.58,0 6.6469,-2.8208 6.6469,-6.4022v-24.8545c0,-3.5803 -3.0652,-6.3967 -6.6438,-6.3983h-0.0031zM7.8399,10.8662h35.1088,0.0031c1.2579,0.0013 2.1277,0.9164 2.1277,1.8821v24.8544c0,0.9666 -0.8714,1.8821 -2.1307,1.8821L11.8924,39.4849l-6.2114,1.8768 0.0633,-0.366 -0.0343,-28.2473c0,-0.9665 0.8706,-1.8821 2.13,-1.8821z"
android:strokeWidth="0.754022"
android:fillColor="#FFFFFFFF"
android:strokeColor="#00000000"/>
<path
android:pathData="m11.5278,32.0849l0,-3.346l7.0363,-3.721q0.3397,-0.1732 0.6551,-0.2596 0.3397,-0.1153 0.6066,-0.1732 0.2912,-0.0288 0.5823,-0.0576l0,-0.2308q-0.2912,-0.0288 -0.5823,-0.1153 -0.2669,-0.0576 -0.6066,-0.1443 -0.3154,-0.1153 -0.6551,-0.2884l-7.0363,-3.721l0,-3.3749l10.8699,5.9132l0,3.6056z"
android:strokeWidth="0.525121"
android:fillColor="#FFFFFFFF"
android:strokeColor="#00000000"/>
<path
android:pathData="m10.9661,15.6112l0,4.8516l7.3742,3.9002c0.0157,0.0077 0.0305,0.0128 0.0461,0.0204 -0.0157,0.0077 -0.0305,0.0128 -0.0461,0.0204l-7.3742,3.9002l0,4.8267l0.7961,-0.4333 11.1995,-6.0969l0,-4.463zM12.0931,17.6933 L21.8346,22.9981l0,2.7446l-9.7414,5.2999l0,-1.8679l6.6912,-3.5416 0.0084,-0.0051c0.1961,-0.0992 0.3826,-0.1724 0.5531,-0.2191l0.0127,0l0.0167,-0.0051c0.2034,-0.0691 0.3777,-0.1209 0.5279,-0.1545l1.0684,-0.1046l0,-1.4644l-0.5154,-0.0497c-0.1632,-0.0153 -0.3288,-0.0505 -0.4944,-0.0997l-0.0167,-0.0051 -0.0167,-0.0051c-0.1632,-0.0352 -0.3552,-0.0811 -0.5656,-0.1344 -0.1802,-0.0668 -0.3706,-0.1479 -0.5698,-0.2492l-0.0084,-0.0051 -6.6912,-3.5416z"
android:strokeWidth="0.525121"
android:fillColor="#FFFFFFFF"
android:strokeColor="#00000000"/>
<path
android:pathData="m26.7503,30.9206l11.6118,0l0,3.1388L26.7503,34.0594Z"
android:strokeWidth="0.525121"
android:fillColor="#FFFFFFFF"
android:strokeColor="#00000000"/>
<path
android:pathData="m26.1875,30.2775l0,0.6427 0,3.7845l12.7371,0l0,-4.4272zM27.3113,31.563l10.4896,0l0,1.8515l-10.4896,0z"
android:strokeWidth="0.525121"
android:fillColor="#FFFFFFFF"
android:strokeColor="#00000000"/>
</vector>

View file

@ -1,31 +1,31 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="22dp"
android:height="22dp"
android:width="50dp"
android:height="50dp"
android:viewportWidth="50"
android:viewportHeight="50">
<path
android:pathData="m7.8399,6.35c-3.58,0 -6.6469,2.817 -6.6469,6.3983v0.003l0.0351,27.8668 -0.8991,6.6347 12.2261,-3.248L42.9487,44.0049c3.58,0 6.6469,-2.8208 6.6469,-6.4022v-24.8545c0,-3.5803 -3.0652,-6.3967 -6.6438,-6.3983h-0.0031zM7.8399,10.8662h35.1088,0.0031c1.2579,0.0013 2.1277,0.9164 2.1277,1.8821v24.8544c0,0.9666 -0.8714,1.8821 -2.1307,1.8821L11.8924,39.4849l-6.2114,1.8768 0.0633,-0.366 -0.0343,-28.2473c0,-0.9665 0.8706,-1.8821 2.13,-1.8821z"
android:strokeWidth="0.754022"
android:fillColor="?android:attr/colorControlNormal"
android:fillColor="#338574"
android:strokeColor="#00000000"/>
<path
android:pathData="m11.5278,32.0849l0,-3.346l7.0363,-3.721q0.3397,-0.1732 0.6551,-0.2596 0.3397,-0.1153 0.6066,-0.1732 0.2912,-0.0288 0.5823,-0.0576l0,-0.2308q-0.2912,-0.0288 -0.5823,-0.1153 -0.2669,-0.0576 -0.6066,-0.1443 -0.3154,-0.1153 -0.6551,-0.2884l-7.0363,-3.721l0,-3.3749l10.8699,5.9132l0,3.6056z"
android:strokeWidth="0.525121"
android:fillColor="?android:attr/colorControlNormal"
android:fillColor="#338574"
android:strokeColor="#00000000"/>
<path
android:pathData="m10.9661,15.6112l0,4.8516l7.3742,3.9002c0.0157,0.0077 0.0305,0.0128 0.0461,0.0204 -0.0157,0.0077 -0.0305,0.0128 -0.0461,0.0204l-7.3742,3.9002l0,4.8267l0.7961,-0.4333 11.1995,-6.0969l0,-4.463zM12.0931,17.6933 L21.8346,22.9981l0,2.7446l-9.7414,5.2999l0,-1.8679l6.6912,-3.5416 0.0084,-0.0051c0.1961,-0.0992 0.3826,-0.1724 0.5531,-0.2191l0.0127,0l0.0167,-0.0051c0.2034,-0.0691 0.3777,-0.1209 0.5279,-0.1545l1.0684,-0.1046l0,-1.4644l-0.5154,-0.0497c-0.1632,-0.0153 -0.3288,-0.0505 -0.4944,-0.0997l-0.0167,-0.0051 -0.0167,-0.0051c-0.1632,-0.0352 -0.3552,-0.0811 -0.5656,-0.1344 -0.1802,-0.0668 -0.3706,-0.1479 -0.5698,-0.2492l-0.0084,-0.0051 -6.6912,-3.5416z"
android:strokeWidth="0.525121"
android:fillColor="?android:attr/colorControlNormal"
android:fillColor="#338574"
android:strokeColor="#00000000"/>
<path
android:pathData="m26.7503,30.9206l11.6118,0l0,3.1388L26.7503,34.0594Z"
android:strokeWidth="0.525121"
android:fillColor="?android:attr/colorControlNormal"
android:fillColor="#338574"
android:strokeColor="#00000000"/>
<path
android:pathData="m26.1875,30.2775l0,0.6427 0,3.7845l12.7371,0l0,-4.4272zM27.3113,31.563l10.4896,0l0,1.8515l-10.4896,0z"
android:strokeWidth="0.525121"
android:fillColor="?android:attr/colorControlNormal"
android:fillColor="#338574"
android:strokeColor="#00000000"/>
</vector>

View file

@ -6,21 +6,21 @@
<path
android:pathData="M7.8398,6.35C4.2598,6.35 1.1932,9.1672 1.1932,12.7486L1.1932,12.7512L1.2283,40.6182L0.3292,47.2529L12.5553,44.0051L35.9384,44.0051L36.5848,39.4849L11.8923,39.4849L5.6808,41.3618L5.7444,40.9954L5.7097,12.7486C5.7097,11.7821 6.5805,10.866 7.8398,10.866L42.9488,10.866L42.9519,10.866C44.2097,10.8673 45.0794,11.7828 45.0794,12.7486L45.0794,25.7395L49.5954,25.7395L49.5954,12.7481C49.5954,9.1677 46.5305,6.3517 42.9519,6.35L42.9488,6.35L7.8398,6.35zM49.5954,31.4735C45.6685,38.326 43.7215,41.7259 42.4176,44.0051L42.9488,44.0051C46.5288,44.0051 49.5954,41.1842 49.5954,37.6029L49.5954,31.4735z"
android:strokeWidth="2.84985"
android:fillColor="#FFFFFFFF"
android:fillColor="#338574"
android:strokeColor="#00000000"/>
<path
android:pathData="m11.5278,32.0849l0,-3.346l7.0363,-3.721q0.3397,-0.1732 0.6551,-0.2596 0.3397,-0.1153 0.6066,-0.1732 0.2912,-0.0288 0.5823,-0.0576l0,-0.2308q-0.2912,-0.0288 -0.5823,-0.1153 -0.2669,-0.0576 -0.6066,-0.1443 -0.3154,-0.1153 -0.6551,-0.2884l-7.0363,-3.721l0,-3.3749l10.8699,5.9132l0,3.6056z"
android:strokeWidth="0.525121"
android:fillColor="#FFFFFFFF"
android:fillColor="#338574"
android:strokeColor="#00000000"/>
<path
android:pathData="m10.9661,15.6112l0,4.8516l7.3742,3.9002c0.0157,0.0077 0.0305,0.0128 0.0461,0.0204 -0.0157,0.0077 -0.0305,0.0128 -0.0461,0.0204l-7.3742,3.9002l0,4.8267l0.7961,-0.4333 11.1995,-6.0969l0,-4.463zM12.0931,17.6933 L21.8346,22.9981l0,2.7446l-9.7414,5.2999l0,-1.8679l6.6912,-3.5416 0.0084,-0.0051c0.1961,-0.0992 0.3826,-0.1724 0.5531,-0.2191l0.0127,0l0.0167,-0.0051c0.2034,-0.0691 0.3777,-0.1209 0.5279,-0.1545l1.0684,-0.1046l0,-1.4644l-0.5154,-0.0497c-0.1632,-0.0153 -0.3288,-0.0505 -0.4944,-0.0997l-0.0167,-0.0051 -0.0167,-0.0051c-0.1632,-0.0352 -0.3552,-0.0811 -0.5656,-0.1344 -0.1802,-0.0668 -0.3706,-0.1479 -0.5698,-0.2492l-0.0084,-0.0051 -6.6912,-3.5416z"
android:strokeWidth="0.525121"
android:fillColor="#FFFFFFFF"
android:fillColor="#338574"
android:strokeColor="#00000000"/>
<path
android:pathData="m41.6796,15.3498c-4.1394,7.2567 -7.8235,13.7146 -10.2159,17.9374h8.5829l-1.8531,12.962c1.2024,-2.1043 3.8969,-6.8095 10.2878,-17.9601h-8.6543z"
android:strokeWidth="1"
android:fillColor="#FFFFFFFF"
android:fillColor="#338574"
android:strokeColor="#00000000"/>
</vector>

View file

@ -5,13 +5,13 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.DetailActivity"
>
tools:context=".ui.DetailActivity">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
style="@style/CardViewBackground"
android:id="@+id/detail_notification_list_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:visibility="gone">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/detail_notification_list"
@ -19,9 +19,7 @@
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:clipToPadding="false"
android:layout_marginTop="10dp"
android:background="?android:attr/selectableItemBackground"
app:layoutManager="LinearLayoutManager"/>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

View file

@ -7,13 +7,10 @@
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:shapeAppearance="?shapeAppearanceLargeComponent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:id="@+id/main_banner_battery"
android:visibility="visible"
>
app:shapeAppearance="?shapeAppearanceLargeComponent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent"
android:id="@+id/main_banner_battery" android:visibility="visible">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -86,64 +83,64 @@
android:layout_height="wrap_content"
app:shapeAppearance="?shapeAppearanceLargeComponent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/main_banner_battery"
android:id="@+id/main_banner_websocket" android:visibility="visible">
android:id="@+id/main_banner_json_stream" android:visibility="visible">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/main_banner_websocket_constraint" android:elevation="5dp">
android:id="@+id/main_banner_json_stream_constraint" android:elevation="5dp">
<ImageView
android:layout_width="28dp"
android:layout_height="28dp" app:srcCompat="@drawable/ic_announcement_orange_24dp"
android:id="@+id/main_banner_websocket_image"
android:id="@+id/main_banner_json_stream_image"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/main_banner_websocket_text"
app:layout_constraintEnd_toStartOf="@id/main_banner_websocket_text"
app:layout_constraintBottom_toBottomOf="@+id/main_banner_websocket_text"
app:layout_constraintTop_toTopOf="@+id/main_banner_json_stream_text"
app:layout_constraintEnd_toStartOf="@id/main_banner_json_stream_text"
app:layout_constraintBottom_toBottomOf="@+id/main_banner_json_stream_text"
android:layout_marginStart="15dp"/>
<TextView
android:id="@+id/main_banner_websocket_text"
android:id="@+id/main_banner_json_stream_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/main_banner_websocket_text"
android:text="@string/main_banner_json_stream_text"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginEnd="15dp" android:layout_marginTop="15dp"
app:layout_constraintStart_toEndOf="@+id/main_banner_websocket_image"
android:layout_marginStart="10dp"
/>
app:layout_constraintStart_toEndOf="@+id/main_banner_json_stream_image"
android:layout_marginStart="10dp" android:autoLink="web"/>
<androidx.constraintlayout.helper.widget.Flow
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:constraint_referenced_ids="main_banner_websocket_remind_later,main_banner_websocket_dontaskagain,main_banner_websocket_enable" app:layout_constraintTop_toBottomOf="@id/main_banner_websocket_text" app:flow_horizontalAlign="end" app:flow_wrapMode="chain" app:flow_horizontalStyle="packed" android:layout_marginEnd="15dp" android:id="@+id/flow" app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="15dp" app:flow_horizontalBias="1"
app:constraint_referenced_ids="main_banner_json_stream_remind_later,main_banner_json_stream_dontaskagain,main_banner_json_stream_learn_mode" app:layout_constraintTop_toBottomOf="@id/main_banner_json_stream_text" app:flow_horizontalAlign="end" app:flow_wrapMode="chain" app:flow_horizontalStyle="packed" android:layout_marginEnd="15dp" android:id="@+id/flow" app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="15dp" app:flow_horizontalBias="1"
app:flow_verticalGap="0dp" app:flow_horizontalGap="0dp"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/main_banner_websocket_remind_later"
android:id="@+id/main_banner_json_stream_remind_later"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_banner_websocket_button_remind_later"
android:text="@string/main_banner_json_stream_button_remind_later"
tools:layout_editor_absoluteX="86dp" tools:layout_editor_absoluteY="83dp"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/main_banner_websocket_dontaskagain"
android:id="@+id/main_banner_json_stream_dontaskagain"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_banner_websocket_button_dismiss"
android:text="@string/main_banner_json_stream_button_dismiss"
tools:layout_editor_absoluteX="260dp" tools:layout_editor_absoluteY="83dp"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/main_banner_websocket_enable"
android:id="@+id/main_banner_json_stream_learn_mode"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_banner_websocket_button_enable_now"
android:text="@string/main_banner_json_stream_button_learn_more"
tools:layout_editor_absoluteX="253dp" tools:layout_editor_absoluteY="131dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
@ -152,19 +149,17 @@
android:id="@+id/main_subscriptions_list_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="10dp"
android:visibility="visible"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/main_banner_websocket">
app:layout_constraintTop_toBottomOf="@id/main_banner_json_stream">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/main_subscriptions_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:clipToPadding="false"
android:background="?android:attr/selectableItemBackground"
app:layoutManager="LinearLayoutManager"/>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.button.MaterialButton
xmlns:android="http://schemas.android.com/apk/res/android"
style="?attr/borderlessButtonStyle"
android:id="@+id/button"
android:text="Button"
android:layout_margin="0dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="0dp"
android:minHeight="0dp"
android:insetBottom="0dp"
android:insetTop="0dp"
android:insetLeft="0dp"
android:insetRight="0dp"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:textSize="14sp"
/>

View file

@ -1,210 +1,128 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" style="@style/CardView"
android:id="@+id/detail_item_card"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
android:layout_marginStart="6dp"
android:layout_marginEnd="6dp"
android:layout_marginBottom="1dp"
android:padding="3dp"
app:cardCornerRadius="3dp"
app:cardElevation="2dp"
app:cardMaxElevation="2dp"
app:cardPreventCornerOverlap="true"
app:cardUseCompatPadding="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/detail_item_layout"
android:layout_width="match_parent"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:orientation="horizontal" android:clickable="true"
android:focusable="true"
>
<TextView
android:text="Sun, October 31, 2021, 10:43:12"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:id="@+id/detail_item_date_text"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="10dp" app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="10dp"/>
<TextView
android:layout_width="10dp"
android:layout_height="10dp" android:id="@+id/detail_item_new_dot"
android:layout_gravity="center"
android:background="@drawable/ic_circle"
android:gravity="center"
app:layout_constraintTop_toTopOf="@+id/detail_item_date_text"
app:layout_constraintBottom_toBottomOf="@+id/detail_item_date_text"
android:layout_marginTop="1dp"
app:layout_constraintStart_toEndOf="@id/detail_item_priority_image"
android:layout_marginStart="5dp"/>
<ImageButton
android:layout_width="46dp"
android:layout_height="26dp" app:srcCompat="@drawable/ic_more_horiz_gray_24dp"
android:id="@+id/detail_item_menu_button"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="5dp"
android:background="?android:attr/selectableItemBackground" android:paddingTop="-5dp"
android:layout_marginTop="5dp"/>
<TextView
android:text="This is a very very very long message. It could be as long as 1024 charaters, which is a lot more than you'd think. No, really so far this message is barely 180 characters long. I can't believe how long 1024 bytes are. This is outrageous. Oh you know what, I think I won't type the whole thing. This seems a little too long for a sample text. Well, anyway, it was nice chatting. So far this message is about 400 bytes long. So maybe just double what you see and that's that."
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/detail_item_message_text"
android:textColor="?android:attr/textColorPrimary"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:autoLink="web"
app:layout_constraintTop_toBottomOf="@id/detail_item_title_text"
app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="10dp"
app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="10dp"
app:layout_constraintBottom_toTopOf="@id/detail_item_attachment_image"/>
<TextView
android:text="This is an optional title. It can also be a little longer but not too long."
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/detail_item_title_text"
android:textColor="?android:attr/textColorPrimary"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:autoLink="web"
app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="10dp"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="10dp" android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@+id/detail_item_date_text"/>
<ImageView
android:layout_width="16dp"
android:layout_height="16dp" app:srcCompat="@drawable/ic_priority_5_24dp"
android:id="@+id/detail_item_priority_image"
app:layout_constraintStart_toEndOf="@+id/detail_item_date_text"
app:layout_constraintTop_toTopOf="@+id/detail_item_date_text"
app:layout_constraintBottom_toBottomOf="@+id/detail_item_date_text" android:layout_marginStart="5dp"/>
<com.google.android.material.imageview.ShapeableImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content" app:srcCompat="@drawable/ic_cancel_gray_24dp"
android:id="@+id/detail_item_attachment_image" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@id/detail_item_message_text"
android:layout_marginStart="10dp" android:layout_marginEnd="10dp"
android:scaleType="centerCrop"
android:adjustViewBounds="true" android:maxHeight="150dp" android:layout_marginTop="5dp"
app:shapeAppearanceOverlay="@style/roundedCornersImageView" android:visibility="visible"
android:layout_marginBottom="3dp" app:layout_constraintBottom_toTopOf="@id/detail_item_tags_text"/>
<TextView
android:text="Tags: ssh, zfs"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/detail_item_tags_text"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="10dp"
app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="10dp"
app:layout_constraintTop_toBottomOf="@id/detail_item_attachment_image"
app:layout_constraintBottom_toTopOf="@id/detail_item_attachment_file_box"
app:layout_constraintHorizontal_bias="0.0" android:layout_marginTop="2dp"
/>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" app:layout_constraintTop_toBottomOf="@id/detail_item_tags_text"
android:id="@+id/detail_item_attachment_file_box" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" android:layout_marginStart="10dp" android:layout_marginEnd="10dp"
app:layout_constraintBottom_toTopOf="@id/detail_item_padding_bottom"
android:visibility="visible" android:layout_marginTop="2dp"
android:background="?android:attr/selectableItemBackground"
android:focusable="true"
android:paddingBottom="6dp" android:paddingTop="6dp" android:paddingEnd="6dp">
<TextView
android:text="Sun, October 31, 2021, 10:43:12"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/detail_item_date_text"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="5dp" app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="12dp"/>
<TextView
android:layout_width="10dp"
android:layout_height="10dp" android:id="@+id/detail_item_new_dot"
android:layout_gravity="center"
android:background="@drawable/ic_circle"
android:gravity="center"
app:layout_constraintTop_toTopOf="@+id/detail_item_date_text"
app:layout_constraintBottom_toBottomOf="@+id/detail_item_date_text"
android:layout_marginTop="1dp"
app:layout_constraintStart_toEndOf="@id/detail_item_priority_image"
android:layout_marginStart="5dp"/>
<ImageButton
android:layout_width="28dp"
android:layout_height="26dp" app:srcCompat="@drawable/ic_more_horiz_gray_24dp"
android:id="@+id/detail_item_menu_button"
app:layout_constraintTop_toTopOf="parent"
android:background="?android:attr/selectableItemBackground" android:paddingTop="-5dp"
app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="3dp"/>
<TextView
android:text="This is a very very very long message. It could be as long as 1024 charaters, which is a lot more than you'd think. No, really so far this message is barely 180 characters long. I can't believe how long 1024 bytes are. This is outrageous. Oh you know what, I think I won't type the whole thing. This seems a little too long for a sample text. Well, anyway, it was nice chatting. So far this message is about 400 bytes long. So maybe just double what you see and that's that."
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/detail_item_message_text"
android:textColor="?android:attr/textColorPrimary"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:autoLink="web"
app:layout_constraintTop_toBottomOf="@id/detail_item_title_text"
app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="12dp"
app:layout_constraintBottom_toTopOf="@id/detail_item_attachment_image" app:layout_constraintEnd_toStartOf="@id/detail_item_icon" android:layout_marginEnd="6dp"/>
<TextView
android:text="This is an optional title. It can also be a little longer but not too long."
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/detail_item_title_text"
android:textColor="?android:attr/textColorPrimary"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:autoLink="web"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="12dp" android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@+id/detail_item_date_text" app:layout_constraintEnd_toStartOf="@id/detail_item_icon" android:layout_marginEnd="6dp" tools:layout_constraintEnd_toStartOf="@id/detail_item_icon"/>
android:clickable="true" android:focusable="true" android:padding="4dp" android:paddingStart="0dp">
<ImageView
android:layout_width="16dp"
android:layout_height="16dp" app:srcCompat="@drawable/ic_priority_5_24dp"
android:id="@+id/detail_item_priority_image"
app:layout_constraintStart_toEndOf="@+id/detail_item_date_text"
app:layout_constraintTop_toTopOf="@+id/detail_item_date_text"
app:layout_constraintBottom_toBottomOf="@+id/detail_item_date_text" android:layout_marginStart="5dp"/>
<com.google.android.material.imageview.ShapeableImageView
android:layout_width="fill_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content" app:srcCompat="@drawable/ic_cancel_gray_24dp"
android:id="@+id/detail_item_attachment_image" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@id/detail_item_message_text"
android:layout_marginStart="12dp" android:layout_marginEnd="6dp"
android:scaleType="centerCrop"
android:adjustViewBounds="true" android:maxHeight="150dp" android:layout_marginTop="7dp"
app:shapeAppearanceOverlay="@style/roundedCornersImageView" android:visibility="visible"
android:layout_marginBottom="3dp" app:layout_constraintBottom_toTopOf="@id/detail_item_tags_text"/>
<TextView
android:text="Tags: ssh, zfs"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/detail_item_tags_text"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="12dp"
app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="6dp"
app:layout_constraintTop_toBottomOf="@id/detail_item_attachment_image"
app:layout_constraintBottom_toTopOf="@id/detail_item_attachment_file_box"
app:layout_constraintHorizontal_bias="0.0" android:layout_marginTop="2dp"
android:id="@+id/detail_item_attachment_file_icon" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="@+id/detail_item_attachment_file_info" android:layout_marginEnd="5dp"
app:layout_constraintBottom_toBottomOf="parent"
/>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" app:layout_constraintTop_toBottomOf="@id/detail_item_tags_text"
android:id="@+id/detail_item_attachment_file_box" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" android:layout_marginStart="12dp" android:layout_marginEnd="6dp"
android:visibility="visible" android:layout_marginTop="2dp"
android:background="?android:attr/selectableItemBackground"
android:clickable="true" android:focusable="true" android:padding="4dp" android:paddingStart="0dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content" app:srcCompat="@drawable/ic_cancel_gray_24dp"
android:id="@+id/detail_item_attachment_file_icon" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="@+id/detail_item_attachment_file_info" android:layout_marginEnd="5dp"
app:layout_constraintBottom_toBottomOf="parent"
/>
<TextView
android:text="attachment.jpg\n58 MB, not downloaded, expires 1/2/2022 10:30 PM"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/detail_item_attachment_file_info"
android:textColor="?android:attr/textColorPrimary"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toEndOf="@+id/detail_item_attachment_file_icon"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/detail_item_attachment_file_icon"
app:layout_constraintBottom_toBottomOf="@+id/detail_item_attachment_file_icon"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
<TextView
android:text="attachment.jpg\n58 MB, not downloaded, expires 1/2/2022 10:30 PM"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/detail_item_attachment_file_box"
android:id="@+id/detail_item_actions_wrapper"
app:layout_constraintStart_toStartOf="parent"
android:id="@+id/detail_item_attachment_file_info"
android:textColor="?android:attr/textColorPrimary"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toEndOf="@+id/detail_item_attachment_file_icon"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="4dp"
android:visibility="gone"
android:padding="0dp" android:layout_marginStart="4dp" android:layout_marginTop="4dp">
<com.google.android.material.button.MaterialButton
android:text="Bing it"
style="?attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="@+id/button2" tools:layout_editor_absoluteY="4dp" tools:layout_editor_absoluteX="171dp" android:textSize="14sp" tools:visibility="visible"/>
<com.google.android.material.button.MaterialButton
android:text="Google it"
style="?attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="@+id/button3" tools:visibility="visible" tools:layout_editor_absoluteY="52dp" tools:layout_editor_absoluteX="4dp" android:textSize="14sp"/>
<com.google.android.material.button.MaterialButton
android:text="DuckDuckGo it"
style="?attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="@+id/button1" tools:visibility="visible" tools:layout_editor_absoluteY="4dp" tools:layout_editor_absoluteX="4dp" android:textSize="14sp" android:layout_margin="0dp"/>
<androidx.constraintlayout.helper.widget.Flow
android:id="@+id/detail_item_actions_flow"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:flow_wrapMode="chain2"
app:flow_horizontalStyle="packed"
app:flow_verticalBias="0"
app:flow_verticalGap="0dp"
app:flow_verticalStyle="packed"
app:flow_verticalAlign="top"
app:flow_horizontalBias="0"
app:flow_horizontalGap="0dp"
app:flow_horizontalAlign="start"
app:flow_firstHorizontalBias="0"
app:flow_firstVerticalBias="0"
app:flow_firstHorizontalStyle="packed"
app:flow_firstVerticalStyle="packed"
app:flow_maxElementsWrap="1"
android:layout_margin="0dp"
android:padding="0dp"
app:constraint_referenced_ids="button1,button2,button3"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="4dp"
android:id="@+id/detail_item_padding_bottom"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/detail_item_actions_wrapper" app:layout_constraintBottom_toBottomOf="parent"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="0dp"
app:srcCompat="@drawable/ic_notification"
android:id="@+id/detail_item_icon"
android:visibility="visible"
android:maxHeight="40dp"
android:maxWidth="40dp"
android:adjustViewBounds="true"
android:scaleType="fitStart"
android:padding="0dp"
app:layout_constraintTop_toTopOf="@+id/detail_item_date_text"
app:layout_constraintBottom_toBottomOf="@+id/detail_item_message_text"
app:layout_constraintEnd_toStartOf="@id/detail_item_menu_button"
android:layout_marginEnd="6dp"/>
<androidx.constraintlayout.widget.Guideline android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/guideline2" app:layout_constraintGuide_begin="27dp" android:orientation="horizontal"/>
app:layout_constraintTop_toTopOf="@+id/detail_item_attachment_file_icon"
app:layout_constraintBottom_toBottomOf="@+id/detail_item_attachment_file_icon"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
<TextView
android:layout_width="match_parent"
android:layout_height="5dp" android:id="@+id/detail_item_padding_bottom"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/detail_item_attachment_file_box"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -5,24 +5,24 @@
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:orientation="horizontal" android:clickable="true"
android:focusable="true" android:paddingEnd="18dp"
android:paddingStart="18dp">
android:focusable="true" android:paddingEnd="15dp"
android:paddingStart="15dp">
<ImageView
android:layout_width="35dp"
android:layout_height="35dp" app:srcCompat="@drawable/ic_sms_gray_24dp"
android:id="@+id/main_item_image" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginTop="17dp" android:scaleType="fitStart"/>
android:layout_marginTop="13dp"/>
<TextView
android:text="ntfy.sh/example"
android:layout_width="0dp"
android:layout_height="wrap_content" android:id="@+id/main_item_text"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/main_item_status"
android:layout_marginStart="12dp" app:layout_constraintStart_toEndOf="@+id/main_item_image"
android:layout_marginStart="10dp" app:layout_constraintStart_toEndOf="@+id/main_item_image"
app:layout_constraintVertical_bias="0.0" android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="?android:attr/textColorPrimary" android:layout_marginTop="10dp"
app:layout_constraintEnd_toStartOf="@id/main_item_notification_disabled_until_image"/>
app:layout_constraintEnd_toStartOf="@+id/main_item_instant_image"/>
<TextView
android:text="89 notifications, reconnecting ... This may wrap in the case of UnifiedPush"
android:layout_width="0dp"

View file

@ -1,49 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
style="?attr/collapsingToolbarLayoutLargeStyle"
android:background="@color/e_background"
android:layout_width="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
android:layout_height="?attr/collapsingToolbarLayoutLargeSize">
<com.google.android.material.appbar.MaterialToolbar
app:navigationIcon="@drawable/e_ic_back"
app:title="@string/eos_settings_title"
android:id="@+id/toolbar"
android:background="@color/e_background"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.core.widget.NestedScrollView>
</LinearLayout>

View file

@ -9,9 +9,9 @@
app:showAsAction="ifRoom" android:icon="@drawable/ic_bolt_outline_white_24dp"/>
<item android:id="@+id/detail_menu_disable_instant" android:title="@string/detail_menu_disable_instant"
android:icon="@drawable/ic_bolt_white_24dp" app:showAsAction="ifRoom"/>
<item android:id="@+id/detail_menu_settings" android:title="@string/detail_menu_settings"/>
<item android:id="@+id/detail_menu_test" android:title="@string/detail_menu_test"/>
<item android:id="@+id/detail_menu_copy_url" android:title="@string/detail_menu_copy_url"/>
<item android:id="@+id/detail_menu_clear" android:title="@string/detail_menu_clear"/>
<item android:id="@+id/detail_menu_test" android:title="@string/detail_menu_test"/>
<!--<item android:id="@+id/detail_menu_settings" android:title="@string/detail_menu_settings"/>-->
<item android:id="@+id/detail_menu_unsubscribe" android:title="@string/detail_menu_unsubscribe"/>
</menu>

View file

@ -8,6 +8,5 @@
<item android:id="@+id/main_menu_settings" android:title="@string/main_menu_settings_title"/>
<item android:id="@+id/main_menu_docs" android:title="@string/main_menu_docs_title"/>
<item android:id="@+id/main_menu_rate" android:title="@string/main_menu_rate_title"/>
<item android:id="@+id/main_menu_donate" android:title="@string/main_menu_donate_title"/>
<item android:id="@+id/main_menu_report_bug" android:title="@string/main_menu_report_bug_title"/>
</menu>

View file

@ -2,12 +2,4 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome>
<inset
android:drawable="@drawable/ic_launcher_monochrome"
android:insetLeft="30%"
android:insetTop="30%"
android:insetRight="30%"
android:insetBottom="30%"/>
</monochrome>
</adaptive-icon>

View file

@ -2,12 +2,4 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome>
<inset
android:drawable="@drawable/ic_launcher_monochrome"
android:insetLeft="30%"
android:insetTop="30%"
android:insetRight="30%"
android:insetBottom="30%"/>
</monochrome>
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

View file

@ -1,71 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="channel_notifications_low_name">أولوية منخفضة</string>
<string name="channel_notifications_max_name">الأولوية القصوى</string>
<string name="channel_notifications_min_name">الحد الأدنى للأولوية</string>
<string name="channel_subscriber_notification_title">الإستماع (إلتقاط) الإشعارات الواردة</string>
<string name="channel_notifications_default_name">الأولوية الافتراضية</string>
<string name="channel_subscriber_service_name">خدمة الاشتراك</string>
<string name="channel_notifications_high_name">أولوية عليا</string>
<string name="channel_notifications_group_default_name">افتراضي</string>
<string name="add_dialog_topic_name_hint">اسم الموضوع، على سبيل المثال phil_alerts</string>
<string name="add_dialog_use_another_server">استخدم خادمًا آخر</string>
<string name="add_dialog_button_cancel">إلغاء</string>
<string name="add_dialog_button_subscribe">اشترك</string>
<string name="add_dialog_button_back">العودة</string>
<string name="add_dialog_button_login">لِج</string>
<string name="add_dialog_error_connection_failed">فشل الاتصال: %1$s</string>
<string name="detail_clear_dialog_permanently_delete">الحذف بشكل نهائي</string>
<string name="detail_clear_dialog_cancel">إلغاء</string>
<string name="detail_delete_dialog_cancel">إلغاء</string>
<string name="detail_instant_delivery_disabled">التسليم الفوري مُعطَّل</string>
<string name="detail_item_menu_cancel">إلغاء التنزيل</string>
<string name="detail_item_menu_save_file">حفظ الملف</string>
<string name="detail_item_menu_copy_url">إنسخ الرابط</string>
<string name="detail_item_menu_copy_contents_copied">تم نسخ الإشعار إلى الحافظة</string>
<string name="user_dialog_button_save">حفظ</string>
<string name="add_dialog_base_urls_dropdown_choose">اختر عنوان URL للخدمة</string>
<string name="add_dialog_login_title">تسجيل الدخول مطلوب</string>
<string name="detail_copied_to_clipboard_message">تم نسخه إلى الحافظة</string>
<string name="detail_instant_delivery_enabled">التسليم الفوري مُفعَّل</string>
<string name="channel_subscriber_notification_instant_text">مشترِك في الإستلام الفوري للمواضيع</string>
<string name="add_dialog_login_username_hint">إسم المستخدم</string>
<string name="add_dialog_login_new_user">مستخدم جديد</string>
<string name="add_dialog_login_password_hint">كلمة المرور</string>
<string name="detail_how_to_example">مثال (باستخدام curl): <br/> <tt> $ curl -d \"أهلًا\" %1$s </tt></string>
<string name="detail_item_snack_deleted">تم حذف الإشعار</string>
<string name="detail_item_snack_undo">إلغاء</string>
<string name="detail_item_menu_copy_contents">نسخ الإشعار</string>
<string name="detail_item_tags">الوسوم: %1$s</string>
<string name="detail_test_message_error">لا يمكن إرسال رسالة: %1$s</string>
<string name="detail_no_notifications_text">لم تتلق بعد أية إشعارات حول هذا الموضوع.</string>
<string name="detail_delete_dialog_permanently_delete">الحذف بشكل نهائي</string>
<string name="channel_subscriber_notification_noinstant_text">تم الاشتراك في المواضيع</string>
<string name="channel_subscriber_notification_noinstant_text_two">مشترك في موضوعين</string>
<string name="channel_subscriber_notification_noinstant_text_three">مشترك في ثلاثة مواضيع</string>
<string name="channel_subscriber_notification_noinstant_text_six">مشترك في ستة مواضيع</string>
<string name="channel_subscriber_notification_noinstant_text_four">مشترك في أربعة مواضيع</string>
<string name="channel_subscriber_notification_noinstant_text_five">مشترك في خمسة مواضيع</string>
<string name="main_menu_settings_title">الإعدادات</string>
<string name="channel_subscriber_notification_noinstant_text_one">مشترك في موضوع واحد</string>
<string name="main_menu_rate_title">قيم البرنامج ⭐</string>
<string name="channel_subscriber_notification_instant_text_two">تم الاشتراك في 2 موضوع فوري</string>
<string name="refresh_message_result">تم استلام %1$d اشعار(ات)</string>
<string name="channel_subscriber_notification_noinstant_text_more">مشترك في %1$d موضوع</string>
<string name="main_menu_notifications_enabled">الاشعارات مفعلة</string>
<string name="main_menu_notifications_disabled_forever">الاشعارات مكتومة</string>
<string name="channel_subscriber_notification_instant_text_six">تم الاشتراك في 6 مواضيع فورية</string>
<string name="channel_subscriber_notification_instant_text_three">تم الاشتراك في 3 مواضيع فورية</string>
<string name="channel_subscriber_notification_instant_text_five">تم الاشتراك في 5 مواضيع فورية</string>
<string name="main_menu_notifications_disabled_until">الاشعارات مكتومة حتي %1$s</string>
<string name="channel_subscriber_notification_instant_text_more">تم الاشتراك في %1$d مواضيع فورية</string>
<string name="main_menu_report_bug_title">التبليغ عن خطأ</string>
<string name="main_action_bar_title">المواضيع المسجلة</string>
<string name="main_action_mode_menu_unsubscribe">الغاء الاشتراك</string>
<string name="main_menu_docs_title">اقرا المراجع</string>
<string name="refresh_message_no_results">كل شئ محدث لاخر تحديث</string>
<string name="channel_subscriber_notification_instant_text_one">تم الاشتراك في 1 موضوع فوري</string>
<string name="channel_subscriber_notification_instant_text_four">تم الاشتراك في 4 مواضيع فورية</string>
<string name="main_menu_donate_title">تبرع 💸</string>
<string name="settings_title">اﻹعدادات</string>
</resources>

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="channel_notifications_low_name">Нисък приоритет</string>
<string name="channel_notifications_default_name">Подразбиран приоритет</string>
<string name="channel_notifications_high_name">Висок приоритет</string>
<string name="channel_notifications_max_name">Най-висок приоритет</string>
<string name="channel_notifications_low_name">Известия (нисък приоритет)</string>
<string name="channel_notifications_default_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">Има абонамент за теми с незабавно доставяне</string>
<string name="channel_subscriber_notification_instant_text_three">Има абонамент за три теми с незабавно доставяне</string>
@ -21,7 +21,7 @@
\n
\n%2$s</string>
<string name="main_menu_notifications_enabled">Известията са включени</string>
<string name="main_menu_notifications_disabled_forever">Известията са заглушени</string>
<string name="main_menu_notifications_disabled_forever">Известията са изключени</string>
<string name="main_menu_settings_title">Настройки</string>
<string name="main_action_mode_delete_dialog_message">Желаете ли да се отпишете от избраните теми и безвъзвратно да премахнете известия\?</string>
<string name="add_dialog_title">Абониране за тема</string>
@ -31,15 +31,15 @@
<string name="add_dialog_login_description">Тази тема изисква да влезете. Въведете потребителско име и парола.</string>
<string name="detail_clear_dialog_message">Наистина ли желаете да премахнете всички известия в темата\?</string>
<string name="detail_delete_dialog_message">Наистина ли желаете да се отпишете от темата и да премахнете всички известия\?</string>
<string name="settings_notifications_muted_until_title">Заглушаване на известия</string>
<string name="settings_notifications_muted_until_title">Изключване на известията</string>
<string name="notification_dialog_tomorrow">До утре</string>
<string name="detail_menu_copy_url">Копиране адреса на темата</string>
<string name="share_topic_title">Споделяне с</string>
<string name="share_suggested_topics">Предложени теми</string>
<string name="settings_notifications_muted_until_show_all">Показват се всички известия</string>
<string name="notification_dialog_forever">До включване</string>
<string name="settings_notifications_muted_until_forever">Известията са заглушени до включването им</string>
<string name="settings_notifications_muted_until_x">Известията са заглушени до %1$s</string>
<string name="settings_notifications_muted_until_forever">Известията са изключени до включването им</string>
<string name="settings_notifications_muted_until_x">Известията са изключени до %1$s</string>
<string name="settings_general_users_summary">Добавяне и премахване на потребители за защитени теми</string>
<string name="settings_general_users_prefs_user_not_used">Не се използва от никоя тема</string>
<string name="settings_general_users_prefs_user_used_by_one">Използва се от %1$s</string>
@ -51,22 +51,22 @@
\nПаролите са премахнати, но не са изброени тук.</string>
<string name="settings_advanced_export_logs_scrub_dialog_empty">Не са променени никакви теми/имена на хостове. Абонирани ли сте\?</string>
<string name="user_dialog_description_add">Тук можете да добавите потребител. Всички теми на сървъра ще използват този потребител.</string>
<string name="channel_notifications_min_name">Най-нисък приоритет</string>
<string name="channel_notifications_min_name">Известия (минимален приоритет)</string>
<string name="channel_subscriber_notification_instant_text_one">Има абонамент за тема с незабавно доставяне</string>
<string name="notification_dialog_muted_forever_toast_message">Известията са заглушени</string>
<string name="notification_dialog_muted_forever_toast_message">Известията са изключени</string>
<string name="channel_subscriber_notification_title">Очаква входящи известия</string>
<string name="channel_subscriber_notification_instant_text_two">Има абонамент за две теми с незабавно доставяне</string>
<string name="add_dialog_description_below">Възможно е темите да не са защитени с парола, затова изберете име, което е трудно за отгатване. След като се абонирате, можете да изпращате известия по PUT или POST.</string>
<string name="notification_dialog_title">Заглушаване на известия</string>
<string name="notification_dialog_title">Изключване на известията</string>
<string name="channel_subscriber_notification_instant_text_more">Има абонамент за %1$d теми с незабавно доставяне</string>
<string name="refresh_message_error_one">Абонаментът не може да бъде обновен: %1$s</string>
<string name="main_menu_notifications_disabled_until">Известията са заглушени до %1$s</string>
<string name="detail_menu_notifications_disabled_until">Известията са заглушени до %1$s</string>
<string name="main_menu_notifications_disabled_until">Известията са изключени до %1$s</string>
<string name="detail_menu_notifications_disabled_until">Известията са изключени до %1$s</string>
<string name="main_how_to_intro">Докоснете бутона с +, за да създадете тема или да се абонирате. След това ще получавате известия на устройството си, след като изпратите съобщения чрез метода PUT или POST.</string>
<string name="detail_how_to_intro">За да изпратите известия в тази тема направете заявка чрез методите PUT или POST към адреса й.</string>
<string name="detail_no_notifications_text">Липсват известия в темата</string>
<string name="detail_how_to_intro">За да изпратите известия в тази тема, просто изпратете PUT или POST към адреса й.</string>
<string name="detail_no_notifications_text">В момента в темата няма известия</string>
<string name="settings_general_default_base_url_message">За да използвате по подразбиране собствен сървър при абониране за нови теми и/или споделяне на теми, въведете адрес на сървъра.</string>
<string name="notification_dialog_muted_until_toast_message">Известията са заглушени до %1$s</string>
<string name="notification_dialog_muted_until_toast_message">Известията са изключени до %1$s</string>
<string name="settings_advanced_export_logs_summary">Дневниците се копират в междинната памет или се изпращат към nopaste.net (собственост на автора на ntfy). Имената на хостовете и темите могат да бъдат цензурирани, но съдържанието на известията никога.</string>
<string name="main_menu_report_bug_title">Доклад за дефект</string>
<string name="main_menu_docs_title">Документация</string>
@ -80,8 +80,9 @@
<string name="main_action_mode_delete_dialog_permanently_delete">Премахване</string>
<string name="main_item_status_unified_push">%1$s (UnifiedPush)</string>
<string name="main_item_status_reconnecting">свързване…</string>
<string name="main_no_subscriptions_text">Липсват абонаменти</string>
<string name="main_no_subscriptions_text">В момента нямате абонаменти</string>
<string name="main_unified_push_toast">Този абонамент се управлява от %1$s чрез UnifiedPush</string>
<string name="main_banner_json_stream_button_learn_more">Научете повече</string>
<string name="add_dialog_button_cancel">Отказ</string>
<string name="add_dialog_button_subscribe">Абониране</string>
<string name="add_dialog_button_back">Назад</string>
@ -98,9 +99,9 @@
<string name="detail_clear_dialog_permanently_delete">Премахване</string>
<string name="detail_clear_dialog_cancel">Отказ</string>
<string name="main_banner_battery_button_remind_later">По-късно</string>
<string name="main_banner_websocket_button_remind_later">По-късно</string>
<string name="main_banner_json_stream_button_remind_later">По-късно</string>
<string name="main_banner_battery_button_dismiss">Отхвърляне</string>
<string name="main_banner_websocket_button_dismiss">Отхвърляне</string>
<string name="main_banner_json_stream_button_dismiss">Отхвърляне</string>
<string name="main_banner_battery_text">Оптимизирането на батерията трябва да е изключено, за да бъдат избегнати забавяния при получаване на известията.</string>
<string name="main_banner_battery_button_fix_now">Настройки</string>
<string name="add_dialog_instant_delivery">Незабавно доставяне в режим на сън</string>
@ -142,12 +143,12 @@
\n%3$s</string>
<string name="settings_title">Настройки</string>
<string name="settings_notifications_header">Известия</string>
<string name="settings_notifications_min_priority_title">Най-нисък приоритет</string>
<string name="settings_notifications_min_priority_title">Mинимален приоритет</string>
<string name="settings_notifications_min_priority_min">Всички</string>
<string name="settings_notifications_min_priority_low">Нисък приоритет и по-висок</string>
<string name="settings_notifications_min_priority_default">Подразбиран приоритет и по-висок</string>
<string name="settings_notifications_min_priority_high">Висок приоритет и по-висок</string>
<string name="settings_notifications_min_priority_max">Само най-висок приоритет</string>
<string name="settings_notifications_min_priority_max">Само максимален приоритет</string>
<string name="settings_notifications_min_priority_summary_max">Показват се известията с приоритет 5 (най-висок)</string>
<string name="settings_notifications_min_priority_summary_any">Показват се всички известия</string>
<string name="settings_notifications_auto_delete_never">Никога</string>
@ -174,7 +175,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,8 +184,9 @@
<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. Методът е изпитан, но може да използва повече батерия.</string>
<string name="detail_test_message">Това е пробно известие от приложението ntfy за Android. То е с приоритет %1$d. Ако изпратите друго, то може да изглежда по различен начин.</string>
<string name="main_banner_json_stream_text">От юни 2022 г. за връзка със сървърите на ntfy ще се използва WebSockets. Не забравяйте да настроите собствения сървър да го поддържа. За да проверите дали поддръжката на WebSocket работи, разрешете я в Настройки, в раздел Протокол за връзка.</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">За свързване със сървъра се използва поток от JSON през HTTP. Методът е остарял и ще бъде премахнат през месец юни 2022 год.</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>
<string name="settings_notifications_min_priority_summary_x_or_higher">Показват се известията с приоритет %1$d (%2$s) или по-висок</string>
@ -237,7 +239,7 @@
<string name="notification_popup_file_download_failed">%1$s
\nФайл: %2$s, неуспешно изтеглен</string>
<string name="settings_notifications_auto_download_title">Изтегляне на прикачени файлове</string>
<string name="settings_notifications_auto_delete_title">Автоматично премахване</string>
<string name="settings_notifications_auto_delete_title">Премахване на известия</string>
<string name="settings_notifications_auto_download_summary_always">Прикачените файлове се изтеглят автоматично</string>
<string name="settings_notifications_auto_download_summary_never">Прикачените файлове не се изтеглят автоматично</string>
<string name="settings_notifications_auto_download_summary_smaller_than_x">Прикачените файлове до %1$s се изтеглят автоматично</string>
@ -277,7 +279,7 @@
<string name="detail_item_cannot_open_not_found">Прикаченият файл не може да бъде отворен: Или е премахнат, или липсва приложение, с което да бъде отворен.</string>
<string name="detail_item_cannot_save">Прикаченият файл не може да бъде запазен: %1$s</string>
<string name="detail_item_cannot_delete">Прикаченият файл не може да бъде премахнат: %1$s</string>
<string name="detail_item_cannot_open_url">Адресът не може да бъде посетен: %1$s</string>
<string name="detail_item_cannot_open_click_url">Адресът не може да бъде посетен: %1$s</string>
<string name="detail_item_download_failed">Прикаченият файл не може да бъде изтеглен: %1$s</string>
<string name="detail_item_download_info_not_downloaded">не е изтеглен</string>
<string name="detail_item_download_info_not_downloaded_expired">не е изтеглен, препратката е с изтекла валидност</string>
@ -285,7 +287,7 @@
<string name="detail_item_download_info_deleted_expired">премахнат, препратката е с изтекла валидност</string>
<string name="detail_item_download_info_deleted_expires_x">премахнат, валидността изтича на %1$s</string>
<string name="detail_item_download_info_download_failed_expired">грешка при изтегляне, препратката е с изтекла валидност</string>
<string name="detail_menu_notifications_disabled_forever">Известията са заглушени</string>
<string name="detail_menu_notifications_disabled_forever">Известията са изключени</string>
<string name="detail_menu_notifications_enabled">Известията са включени</string>
<string name="detail_item_download_info_not_downloaded_expires_x">не е изтеглен, валидността изтича на %1$s</string>
<string name="detail_item_download_info_downloading_x_percent">%1$d%% изтеглен</string>
@ -293,54 +295,10 @@
<string name="detail_item_download_info_download_failed_expires_x">грешка при изтегляне, валидността изтича на %1$s</string>
<string name="share_content_image_error">Изображението не може да бъде отворено: %1$s</string>
<string name="share_content_file_error">Информацията за файла не може да бъде прочетена: %1$s</string>
<string name="settings_notifications_priority_min">най-нисък</string>
<string name="settings_notifications_priority_min">минимален</string>
<string name="settings_notifications_priority_low">нисък</string>
<string name="settings_notifications_priority_default">подразбиран</string>
<string name="settings_notifications_priority_max">най-висок</string>
<string name="settings_notifications_priority_max">максимален</string>
<string name="settings_notifications_priority_high">висок</string>
<string name="detail_deep_link_subscribed_toast_message">Абонирани сте за темата %1$s</string>
<string name="settings_notifications_channel_prefs_summary">Отмяна на „Не безпокойте“, звуци и т.н.</string>
<string name="settings_notifications_channel_prefs_title">Настройки на категорията</string>
<string name="notification_popup_user_action_failed">%1$s е неуспешно: %2$s</string>
<string name="channel_subscriber_notification_instant_text_five">Има абонамент за пет теми с незабавно доставяне</string>
<string name="channel_subscriber_notification_instant_text_six">Има абонамент за шест теми с незабавно доставяне</string>
<string name="channel_subscriber_notification_noinstant_text_five">Има абонамент за пет теми</string>
<string name="channel_subscriber_notification_noinstant_text_six">Има абонамент за шест теми</string>
<string name="detail_settings_notifications_instant_title">Незабавно доставяне</string>
<string name="detail_settings_notifications_instant_summary_on">Известията се доставят незабавно. Изисква услуга на преден план и изразходва повече батерия.</string>
<string name="detail_settings_appearance_header">Външен вид</string>
<string name="detail_settings_appearance_icon_set_title">Значка за абонамент</string>
<string name="detail_settings_appearance_icon_set_summary">Задаване на значка, която да бъде показвана в известията</string>
<string name="detail_settings_appearance_icon_remove_title">Значка за абонамент (докоснете, за да премахнете)</string>
<string name="detail_settings_appearance_icon_remove_summary">Значка, показвана в известията на тази тема</string>
<string name="detail_settings_global_setting_title">Използване на общите настройки</string>
<string name="detail_settings_notifications_instant_summary_off">Известията се доставят с помощта на Firebase. Доставката може да се забави, но изразходва по-малко батерия.</string>
<string name="detail_settings_appearance_icon_error_saving">Значката не може да бъде запазена: %1$s</string>
<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>
<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>
<string name="detail_settings_appearance_display_name_default_summary">%1$s (по подразбиране)</string>
<string name="detail_settings_appearance_display_name_title">Наименование</string>
<string name="detail_settings_appearance_display_name_message">Задайте име на абонамента. За да върнете името по подразбиране (%1$s) оставете празно.</string>
<string name="detail_settings_about_header">Относно</string>
<string name="detail_settings_about_topic_url_title">Адрес на темата</string>
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">Копирано в междинната памет</string>
<string name="main_menu_donate_title">Даряване 💸</string>
<string name="detail_item_cannot_open_apk">Ntfy не може да инсталира получени приложения. Вместо това изтеглете чрез браузъра. За подробности вижте дефект №531.</string>
<string name="channel_notifications_group_default_name">Подразбирани</string>
<string name="detail_settings_notifications_dedicated_channels_title">Потребителски настройки за известия</string>
<string name="detail_settings_notifications_dedicated_channels_summary_on">Използва потребителски настройки за този абонамент</string>
<string name="settings_notifications_insistent_max_priority_title">Продължително сигнализиране за най-високия приоритет</string>
<string name="settings_notifications_insistent_max_priority_summary_disabled">Известията с най-висок приоритет сигнализират веднъж</string>
<string name="detail_settings_notifications_open_channels_title">Настройки на известията</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_enabled">Продължително сигнализиране</string>
<string name="detail_settings_notifications_open_channels_summary">Отмяна на „Не безпокойте“, звуци и т.н.</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_disabled">Единично сигнализиране</string>
<string name="detail_settings_notifications_dedicated_channels_summary_off">Подразбирани настройки (отмяна на „Не безпокойте“, звуци и т.н.)</string>
<string name="settings_notifications_insistent_max_priority_summary_enabled">Известията с най-висок приоритет сигнализират, докато не бъдат затворени</string>
<string name="settings_advanced_unifiedpush_summary_enabled">ntfy ще работи като дистрибутор на UnifiedPush</string>
<string name="settings_advanced_unifiedpush_title">Включване на UnifiedPush</string>
<string name="settings_advanced_unifiedpush_summary_disabled">ntfy няма да работи като дистрибутор на UnifiedPush</string>
</resources>

View file

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="channel_notifications_low_name">কম গুরুত্ব</string>
<string name="channel_notifications_min_name">সর্বনিম্ন গুরুত্ব</string>
<string name="channel_notifications_default_name">স্বাভাবিক গুরুত্ব</string>
<string name="channel_notifications_max_name">সর্বোচ্চ্য গুরুত্ব</string>
<string name="channel_notifications_group_default_name">স্বাভাবিক</string>
<string name="channel_notifications_high_name">বেশি গুরুত্ব</string>
<string name="channel_subscriber_notification_title">আগত নোটিফিকেশন এর জন্য অপেক্ষা করা হচ্ছে</string>
<string name="channel_subscriber_notification_instant_text">তাত্ক্ষণিক পাওয়া বিষয়গুলোতে যোগ দেওয়া হয়েছে</string>
</resources>

View file

@ -1,346 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="channel_notifications_min_name">Prioritat mínima</string>
<string name="channel_notifications_low_name">Prioritat baixa</string>
<string name="channel_notifications_default_name">Prioritat per defecte</string>
<string name="channel_notifications_high_name">Prioritat alta</string>
<string name="channel_notifications_max_name">Prioritat màxima</string>
<string name="channel_subscriber_service_name">Servei Subscripció</string>
<string name="main_menu_donate_title">Donar 💸</string>
<string name="main_item_status_reconnecting">reconnectant…</string>
<string name="channel_subscriber_notification_title">Escoltant notificacions entrants</string>
<string name="channel_subscriber_notification_instant_text">Subscrit per entrega instantània de temes</string>
<string name="channel_subscriber_notification_instant_text_one">Subscrit per entrega instantània d\'un tema</string>
<string name="channel_subscriber_notification_instant_text_two">Subscrit per dues entregues instantànies de temes</string>
<string name="channel_subscriber_notification_instant_text_three">Subscrit per tres entregues instantànies de temes</string>
<string name="channel_subscriber_notification_instant_text_four">Subscrit per quatre entregues instantànies de temes</string>
<string name="channel_subscriber_notification_instant_text_five">Subscrit per cinc entregues instantànies de temes</string>
<string name="channel_subscriber_notification_instant_text_six">Subscrit per sis entregues instantànies de temes</string>
<string name="channel_subscriber_notification_instant_text_more">Subscrit per %1$d entregues instantànies de temes</string>
<string name="channel_subscriber_notification_noinstant_text">Subscrit als temes</string>
<string name="channel_subscriber_notification_noinstant_text_one">Subscrit a un tema</string>
<string name="channel_subscriber_notification_noinstant_text_two">Subscrit a dos temes</string>
<string name="channel_subscriber_notification_noinstant_text_three">Subscrit a tres temes</string>
<string name="channel_subscriber_notification_noinstant_text_six">Subscrit a sis temes</string>
<string name="main_action_mode_delete_dialog_permanently_delete">Eliminat permanentment</string>
<string name="main_action_mode_delete_dialog_cancel">Cancel·lar</string>
<string name="main_item_status_text_one">%1$d notificació</string>
<string name="channel_subscriber_notification_noinstant_text_more">Subscrit a %1$d temes</string>
<string name="channel_subscriber_notification_noinstant_text_four">Subscrit a quatre temes</string>
<string name="channel_subscriber_notification_noinstant_text_five">Subscrit a cinc temes</string>
<string name="refresh_message_result">%1$d notificacions rebudes</string>
<string name="refresh_message_no_results">Tot està actualitzat</string>
<string name="refresh_message_error">No es poden actualitzar %1$d subscripciones
\n
\n%2$s</string>
<string name="refresh_message_error_one">No s\'ha pogut actualitzar la subscripció: %1$s</string>
<string name="main_action_bar_title">Temes subscrits</string>
<string name="main_menu_notifications_enabled">Notificacions activades</string>
<string name="main_menu_notifications_disabled_forever">Notificacions silenciades</string>
<string name="main_menu_notifications_disabled_until">Notificacions silenciades fins: %1$s</string>
<string name="main_menu_settings_title">Ajustos</string>
<string name="main_menu_report_bug_title">Reportar un problema</string>
<string name="main_menu_docs_title">Llegir la documentació</string>
<string name="main_menu_rate_title">Valora la aplicació ⭐</string>
<string name="main_action_mode_menu_unsubscribe">Donar-se de baixa</string>
<string name="main_action_mode_delete_dialog_message">Donar-se de baixa del tema(es) seleccionat(s) permanentment i eliminar totes les notificacions\?</string>
<string name="main_item_status_text_not_one">%1$d notificacions</string>
<string name="channel_notifications_group_default_name">Per defecte</string>
<string name="main_item_date_yesterday">ahir</string>
<string name="main_add_button_description">Afegir subscripció</string>
<string name="main_how_to_intro">Prem + per crear o subscriure\'t a un tema. Després rebràs notificacions al teu dispositiu quan enviïs missatges mitjançant PUT o POST.</string>
<string name="main_no_subscriptions_text">Sembla que encara no tens cap subscripció.</string>
<string name="main_banner_battery_text">L\'optimització de la bateria hauria de ser desactivada per tal d\'evitar problemes amb l\'entrega de notificacions.</string>
<string name="main_banner_websocket_button_dismiss">Descartar</string>
<string name="detail_test_message_error_unauthorized_anon">No es pot enviar el missatge: No es permeten publicacions anònimes.</string>
<string name="detail_instant_delivery_disabled">Entrega instantània desactivada</string>
<string name="detail_item_menu_copy_contents">Copiar la notificació</string>
<string name="detail_item_menu_copy_contents_copied">Notificació copiada al porta-retalls</string>
<string name="detail_menu_test">Enviar notificació de prova</string>
<string name="notification_dialog_save">Guardar</string>
<string name="main_banner_battery_button_remind_later">Preguntar més endavant</string>
<string name="main_banner_battery_button_dismiss">Descartar</string>
<string name="main_banner_battery_button_fix_now">Arreglar ara</string>
<string name="main_banner_websocket_button_remind_later">Preguntar més endavant</string>
<string name="add_dialog_button_back">Enrere</string>
<string name="add_dialog_title">Subscriure\'s a un tema</string>
<string name="detail_deep_link_subscribed_toast_message">Subscrit al tema %1$s</string>
<string name="detail_item_tags">Etiquetes: %1$s</string>
<string name="detail_test_message_error_too_large">No es pot enviar el missatge: L\'adjunt és massa gran.</string>
<string name="detail_item_snack_undo">Desfer</string>
<string name="detail_item_menu_delete">Elimina arxiu</string>
<string name="detail_item_menu_download">Descarrega l\'arxiu</string>
<string name="detail_item_menu_cancel">Cancel·la la descàrrega</string>
<string name="detail_item_menu_copy_url">Copiar la URL</string>
<string name="detail_item_menu_copy_url_copied">URL copiada al porta-retalls</string>
<string name="detail_item_cannot_open_url">No es pot obrir la URL: %1$s</string>
<string name="detail_item_cannot_save">No es pot guardar l\'adjunt: %1$s</string>
<string name="detail_item_cannot_delete">No es pot eliminar l\'adjunt: %1$s</string>
<string name="detail_action_mode_menu_delete">Eliminar</string>
<string name="detail_action_mode_delete_dialog_permanently_delete">Eliminar definitivament</string>
<string name="detail_action_mode_delete_dialog_cancel">Cancel·lar</string>
<string name="detail_settings_title">Configuració de la subscripció</string>
<string name="share_title">Compartir</string>
<string name="share_menu_send">Compartir</string>
<string name="share_content_image_error">No es pot llegir la imatge: %1$s</string>
<string name="share_content_image_text">S\'ha compartit una imatge amb tu</string>
<string name="share_content_file_text">S\'ha compartit un arxiu amb tu</string>
<string name="share_content_file_error">No es pot llegir la informació de l\'arxiu: %1$s</string>
<string name="share_topic_title">Compartir amb</string>
<string name="share_successful">Missatge publicat</string>
<string name="detail_test_title">Test: Pots definir un títol.</string>
<string name="detail_test_message">Això es una notificació de prova de l\'aplicació per Android de ntfy. Té un nivell de prioritat %1$d. Si n\'envies una altra, pot ser diferent.</string>
<string name="detail_test_message_error">No es pot enviar el missatge: %1$s</string>
<string name="detail_test_message_error_unauthorized_user">No es pot enviar el missatge: L\'usuari \"%1$s\" no està autoritzat.</string>
<string name="detail_copied_to_clipboard_message">Copiat al porta-retalls</string>
<string name="detail_item_snack_deleted">Notificació eliminada</string>
<string name="detail_item_menu_open">Obre arxiu</string>
<string name="detail_item_menu_save_file">Guardar l\'arxiu</string>
<string name="detail_item_cannot_download">No es pot obrir o descarregar l\'adjunt. L\'enllaç ha caducat i no es pot trobar un arxiu local.</string>
<string name="detail_item_download_failed">No s\'ha pogut descarregar l\'adjunt: %1$s</string>
<string name="detail_item_download_info_not_downloaded">no descarregat</string>
<string name="detail_item_download_info_not_downloaded_expired">no descarregat, enllaç caducat</string>
<string name="detail_item_download_info_downloading_x_percent">%1$d%% descarregat</string>
<string name="detail_item_download_info_deleted">eliminat</string>
<string name="detail_item_download_info_deleted_expired">eliminat, enllaç caducat</string>
<string name="add_dialog_topic_name_hint">Nom del tema, p. ex. alertes_josep</string>
<string name="add_dialog_base_urls_dropdown_clear">Esborra URL de servei</string>
<string name="detail_no_notifications_text">Encara no has rebut cap notificació en aquest tema.</string>
<string name="detail_how_to_intro">Per enviar notificacions en aquest tema, fes PUT o POST a la URL del tema.</string>
<string name="detail_how_to_example">Exemple (usant curl):<br/><tt>$ curl -d \"Hola\" %1$s</tt></string>
<string name="main_unified_push_toast">Aquesta subscripció és gestionada per %1$s via UnifiedPush</string>
<string name="main_how_to_link">Instruccions detallades disponibles a ntfy.sh i a la documentació.</string>
<string name="main_banner_websocket_text">WebSockets és el mètode recomanat per connectar-te al teu servidor. Pot millorar el rendiment de la bateria, però pot requerir <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">configuració addicional al teu proxy</a>. Aquesta opció pot ser habil·litada a Configuració.</string>
<string name="main_banner_websocket_button_enable_now">Activar ara</string>
<string name="add_dialog_description_below">Els temes poden no estar protegits per contrasenya, tria un nom difícil d\'endevinar. Un cop subscrit podràs publicar notificacions PUT/POST.</string>
<string name="add_dialog_use_another_server">Usar un altre servidor</string>
<string name="add_dialog_use_another_server_description">Introdueix URLs a sota per subscriure\'t a temes d\'altres servidors.</string>
<string name="add_dialog_instant_delivery_description">Assegura que els missatges s\'entreguin immediatament, fins i tot amb el dispositiu inactiu.</string>
<string name="add_dialog_button_cancel">Cancel·lar</string>
<string name="add_dialog_instant_delivery">Entrega instantània en mode Descans</string>
<string name="add_dialog_foreground_description">L\'entrega instantània sempre està activada per a amfitrions diferents de %1$s.</string>
<string name="add_dialog_button_subscribe">Subscriure</string>
<string name="add_dialog_button_login">Entrar</string>
<string name="add_dialog_error_connection_failed">Connexió fallida: %1$s</string>
<string name="add_dialog_login_title">Inici de sessió necessari</string>
<string name="add_dialog_login_description">Aquest tema necessita que iniciïs sessió. Introdueix nom d\'usuari i contrasenya.</string>
<string name="add_dialog_login_username_hint">Nom d\'usuari</string>
<string name="add_dialog_login_password_hint">Contrasenya</string>
<string name="add_dialog_login_error_not_authorized">Inici de sessió fallit. L\'usuari %1$s no està autoritzat.</string>
<string name="add_dialog_login_new_user">Nou usuari</string>
<string name="add_dialog_base_urls_dropdown_choose">Tria URL de servei</string>
<string name="detail_how_to_link">Instruccions detallades disponibles a ntfy.sh i a la documentació.</string>
<string name="detail_clear_dialog_message">Vols esborrar totes les notificacions d\'aquest tema\?</string>
<string name="detail_clear_dialog_permanently_delete">Eliminar definitivament</string>
<string name="detail_clear_dialog_cancel">Cancel·lar</string>
<string name="detail_delete_dialog_message">Vols eliminar la subscripció a aquest tema i totes les notificacions\?</string>
<string name="detail_delete_dialog_permanently_delete">Eliminar definitivament</string>
<string name="detail_delete_dialog_cancel">Cancel·lar</string>
<string name="detail_instant_delivery_enabled">Entrega instantània activada</string>
<string name="detail_item_saved_successfully">Guardat amb el nom \"%1$s\" a la carpeta \"Downloads\"</string>
<string name="detail_item_cannot_open">No es pot obrir l\'adjunt: %1$s</string>
<string name="detail_item_cannot_open_not_found">No es pot obrir l\'adjunt: L\'arxiu pot haver estat eliminat, o potser cap aplicació instal·lada el pot obrir.</string>
<string name="detail_item_download_info_not_downloaded_expires_x">no descarregat, caduca al %1$s</string>
<string name="detail_item_download_info_deleted_expires_x">eliminat, l\'enllaç caduca al %1$s</string>
<string name="detail_item_download_info_download_failed_expires_x">descàrrega fallida, l\'enllaç caduca el %1$s</string>
<string name="detail_menu_disable_instant">Desactivar entrega instantània</string>
<string name="detail_menu_copy_url">Copiar adreça del tema</string>
<string name="detail_item_download_info_download_failed">descàrrega fallida</string>
<string name="detail_menu_notifications_enabled">Notificacions activades</string>
<string name="detail_menu_clear">Eliminar totes les notificacions</string>
<string name="detail_menu_settings">Configuració de la subscripció</string>
<string name="detail_item_download_info_download_failed_expired">descàrrega fallida, enllaç caducat</string>
<string name="detail_menu_notifications_disabled_forever">Notificacions silenciades</string>
<string name="share_suggested_topics">Temes suggerits</string>
<string name="notification_dialog_title">Silenciar notificacions</string>
<string name="detail_menu_notifications_disabled_until">Notificacions silenciades fins %1$s</string>
<string name="notification_dialog_cancel">Cancel·lar</string>
<string name="detail_menu_enable_instant">Activar entrega instantània</string>
<string name="detail_item_cannot_open_apk">Les aplicacions ja no poden ser instal·lades. Descarrega-les a través del navegador. Pots trobar més detalls a #531.</string>
<string name="detail_menu_unsubscribe">Eliminar subscripció</string>
<string name="detail_action_mode_menu_copy">Copiar</string>
<string name="detail_action_mode_delete_dialog_message">Eliminar definitivament la notificació\?</string>
<string name="share_content_title">Vista prèvia del missatge</string>
<string name="share_content_text_hint">Afegeix contingut per compartir aquí</string>
<string name="notification_dialog_enabled_toast_message">Notificacions reactivades</string>
<string name="notification_dialog_muted_forever_toast_message">Notificacions silenciades</string>
<string name="notification_dialog_muted_until_toast_message">Notificacions silenciades fins a %1$s</string>
<string name="notification_dialog_show_all">Mostrar totes les notificacions</string>
<string name="notification_dialog_30min">30 minuts</string>
<string name="notification_dialog_1h">1 hora</string>
<string name="notification_dialog_2h">2 hores</string>
<string name="notification_dialog_8h">8 hores</string>
<string name="notification_dialog_tomorrow">Fins demà</string>
<string name="notification_dialog_forever">Fins que es reactivi</string>
<string name="settings_notifications_header">Notificacions</string>
<string name="settings_notifications_min_priority_title">Prioritat mínima</string>
<string name="settings_notifications_min_priority_summary_any">Mostrant totes les notificacions</string>
<string name="settings_notifications_min_priority_summary_x_or_higher">Mostrar notificacions de prioritat %1$d (%2$s) o superior</string>
<string name="settings_notifications_min_priority_summary_max">Mostrar notificacions si la prioritat és 5 (màxima)</string>
<string name="settings_notifications_priority_low">baixa</string>
<string name="settings_notifications_priority_default">normal</string>
<string name="settings_notifications_priority_high">alta</string>
<string name="settings_notifications_priority_min">mín</string>
<string name="settings_notifications_priority_max">màx</string>
<string name="settings_notifications_channel_prefs_title">Configuració de canal</string>
<string name="settings_notifications_channel_prefs_summary">Sobreescriure No Molestar, sons, etc.</string>
<string name="settings_notifications_auto_download_title">Descarregar adjunts</string>
<string name="settings_notifications_auto_download_summary_always">Descarregar automàticament tots els adjunts</string>
<string name="settings_notifications_auto_download_summary_smaller_than_x">Descarregar automàticament adjunts fins a %1$s</string>
<string name="settings_notifications_auto_download_never">No descarregar mai res automàticament</string>
<string name="settings_notifications_auto_download_always">Descarregar automàticament tot</string>
<string name="settings_notifications_auto_delete_summary_one_week">Eliminar automàticament les notificacions al cap d\'una setmana</string>
<string name="settings_notifications_auto_delete_one_day">Al cap d\'un dia</string>
<string name="settings_notifications_auto_delete_never">Mai</string>
<string name="settings_notifications_auto_delete_three_days">Al cap de 3 dies</string>
<string name="settings_notifications_auto_delete_one_week">Al cap d\'una setmana</string>
<string name="settings_notifications_insistent_max_priority_title">Mantenir alertes per prioritat màxima</string>
<string name="settings_notifications_insistent_max_priority_summary_enabled">Alertar contínuament de les notificacions de prioritat màxima fins que es descartin</string>
<string name="settings_notifications_insistent_max_priority_summary_disabled">Alertar un sol cop per notificacions de prioritat màxima</string>
<string name="settings_general_default_base_url_title">Servidor predeterminat</string>
<string name="settings_general_default_base_url_message">Introdueix la URL base del teu servidor per usar-lo com a predeterminat a l\'hora de subscriure\'t a nous temes o compartir a temes.</string>
<string name="settings_general_default_base_url_default_summary">%1$s (predeterminat)</string>
<string name="settings_general_users_title">Gestionar usuaris</string>
<string name="settings_general_users_prefs_user_add">Afegir usuaris</string>
<string name="settings_general_users_prefs_user_add_title">Afegir nou usuari</string>
<string name="settings_general_users_prefs_user_add_summary">Crear nou usuari per a un nou servidor</string>
<string name="settings_general_dark_mode_summary_system">Usant el predeterminat del sistema</string>
<string name="settings_general_dark_mode_summary_light">Mode clar activat</string>
<string name="settings_general_dark_mode_summary_dark">Mode fosc activat. Que ets un vampir\?</string>
<string name="settings_general_dark_mode_entry_system">Usar predeterminat del sistema</string>
<string name="settings_backup_restore_backup_summary">Exportar configuració, notificacions i usuaris</string>
<string name="settings_backup_restore_restore_title">Recuperar des d\'arxiu</string>
<string name="settings_backup_restore_restore_summary">Importar configuració, notificacions i usuaris</string>
<string name="settings_general_dark_mode_entry_light">Mode clar</string>
<string name="settings_backup_restore_restore_failed">Recuperació fallida: %1$s</string>
<string name="settings_advanced_header">Avançat</string>
<string name="settings_advanced_broadcast_title">Publicar missatges</string>
<string name="settings_advanced_broadcast_summary_enabled">Les aplicacions poden rebre notificacions d\'entrada com a missatges</string>
<string name="settings_advanced_record_logs_summary_enabled">Gravant (fins a 1000 entrades) al dispositiu…</string>
<string name="settings_advanced_export_logs_title">Copiar/carregar registres</string>
<string name="settings_advanced_export_logs_summary">Copiar registres al porta-retalls, o carregar-los a nopaste.net (propietat de l\'autor de ntfy). Els noms de host i els temes poden ser censurats, les notificacions mai.</string>
<string name="settings_advanced_export_logs_entry_copy_original">Copiar al porta-retalls</string>
<string name="settings_advanced_export_logs_entry_copy_scrubbed">Copiar al porta-retalls (censurat)</string>
<string name="detail_settings_notifications_dedicated_channels_summary_off">Usant configuració predeterminada (sons, sobreescriure No Molestar, etc.)</string>
<string name="detail_settings_notifications_open_channels_title">Configuració de notificacions</string>
<string name="detail_settings_notifications_open_channels_summary">Sobreescriure No Molestar, sons, etc.</string>
<string name="detail_settings_appearance_icon_error_saving">No s\'ha pogut guardar la icona: %1$s</string>
<string name="detail_settings_appearance_display_name_title">Nom</string>
<string name="detail_settings_appearance_display_name_message">Tria un nom personalitzat per a aquesta subscripció. Deixa en blanc per usar el predeterminat (%1$s).</string>
<string name="detail_settings_appearance_display_name_default_summary">%1$s (predeterminat)</string>
<string name="detail_settings_global_setting_title">Usar configuració global</string>
<string name="detail_settings_global_setting_suffix">usant configuració global</string>
<string name="detail_settings_about_topic_url_title">URL del tema</string>
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">Copiat al porta-retalls</string>
<string name="user_dialog_title_add">Afegir usuari</string>
<string name="user_dialog_description_edit">Pots editar el nom d\'usuari o la contrasenya de l\'usuari seleccionat, o eliminar-lo.</string>
<string name="user_dialog_base_url_hint">URL de servei</string>
<string name="main_item_status_unified_push">%1$s (UnifiedPush)</string>
<string name="settings_notifications_auto_delete_one_month">Al cap d\'un mes</string>
<string name="settings_general_users_prefs_title">Usuaris</string>
<string name="settings_general_users_prefs_user_not_used">No usat per cap tema</string>
<string name="settings_general_dark_mode_title">Mode fosc</string>
<string name="settings_advanced_connection_protocol_title">Protocol de connexió</string>
<string name="notification_popup_file_downloading">Descarregant %1$s, %2$d%%
\n%3$s</string>
<string name="settings_title">Configuració</string>
<string name="settings_notifications_muted_until_show_all">Mostrant totes les notificacions</string>
<string name="settings_notifications_muted_until_forever">Notificacions silenciades fins que es reactivin</string>
<string name="settings_notifications_muted_until_x">Notificacions silenciades fins %1$s</string>
<string name="settings_notifications_min_priority_min">Qualsevol prioritat</string>
<string name="settings_notifications_min_priority_low">Prioritat baixa i superiors</string>
<string name="settings_notifications_min_priority_max">Només prioritat màxima</string>
<string name="settings_advanced_unifiedpush_title">Activar UnifiedPush</string>
<string name="settings_advanced_unifiedpush_summary_enabled">ntfy actuarà com a distribuidor de UnifiedPush</string>
<string name="settings_advanced_unifiedpush_summary_disabled">ntfy no actuarà com a distribuidor de UnifiedPush</string>
<string name="settings_advanced_record_logs_summary_disabled">Activar registre per poder compartir-lo més endavant per resoldre problemes.</string>
<string name="settings_advanced_clear_logs_title">Eliminar registres</string>
<string name="settings_advanced_export_logs_entry_upload_scrubbed">Carregar i copiar enllaç (censurat)</string>
<string name="settings_advanced_clear_logs_summary">Eliminar registres i tornar a començar</string>
<string name="settings_advanced_clear_logs_deleted_toast">Registres eliminats</string>
<string name="settings_advanced_export_logs_copied_logs">Registres copiats al porta-retalls</string>
<string name="settings_advanced_export_logs_uploading">Carregant registre…</string>
<string name="settings_advanced_export_logs_copied_url">Registres carregats i URL copiada</string>
<string name="settings_advanced_export_logs_error_uploading">Ha fallat la càrrega de registres: %1$s</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Usa un flux JSON a través d\'HTTP per tal de connectar-te al servidor. Aquest mètode és robust, però pot consumir molta bateria.</string>
<string name="settings_about_version_title">Versió</string>
<string name="settings_advanced_connection_protocol_summary_ws">Usa WebSockets per connectar al servidor. Aquest és el mètode recomanat, però pot necessitar configuració addicional al teu proxy.</string>
<string name="settings_about_version_format">ntfy %1$s (%2$s)</string>
<string name="detail_settings_notifications_instant_title">Entrega instantània</string>
<string name="detail_settings_notifications_instant_summary_on">Les notificacions s\'entreguen instantàniament. Requereix d\'un servei en primer pla i consumeix molta bateria.</string>
<string name="detail_settings_notifications_instant_summary_off">Les notificacions s\'entreguen usant FireBase. L\'entrega es pot retardar, però consumeix menys bateria.</string>
<string name="detail_settings_notifications_dedicated_channels_title">Configuració personalitzada de notificacions</string>
<string name="detail_settings_notifications_dedicated_channels_summary_on">Usant configuració personalitzada en aquesta subscripció</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_enabled">Mantenir alertes</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_disabled">Alertar un sol cop</string>
<string name="detail_settings_appearance_icon_set_title">Icona de subscripció</string>
<string name="detail_settings_about_header">Quant a</string>
<string name="detail_settings_appearance_icon_remove_title">Icona de subscripció (prem per eliminar)</string>
<string name="user_dialog_title_edit">Editar usuari</string>
<string name="user_dialog_description_add">Pots afegir un usuari aquí. Tots els temes del servidor usaran aquest usuari.</string>
<string name="user_dialog_username_hint">Nom d\'usuari</string>
<string name="user_dialog_button_cancel">Cancel·lar</string>
<string name="notification_popup_action_open">Obrir</string>
<string name="notification_popup_action_browse">Explorar</string>
<string name="notification_popup_action_download">Descarregar</string>
<string name="notification_popup_action_cancel">Cancel·lar</string>
<string name="notification_popup_file">%1$s
\nArxiu: %2$s</string>
<string name="notification_popup_file_download_successful">%1$s
\nArxiu: %2$s, descarregat</string>
<string name="notification_popup_file_download_failed">%1$s
\nArxiu: %2$s, descàrrega fallida</string>
<string name="notification_popup_user_action_failed">%1$s fallida: %2$s</string>
<string name="settings_notifications_muted_until_title">Silenciar notificacions</string>
<string name="settings_notifications_min_priority_default">Prioritat normal i superiors</string>
<string name="settings_notifications_min_priority_high">Prioritat alta i superiors</string>
<string name="settings_notifications_auto_download_100k">Si inferior a 100 kB</string>
<string name="settings_notifications_auto_download_500k">Si inferior a 500 kB</string>
<string name="settings_notifications_auto_download_1m">Si inferior a 1 MB</string>
<string name="settings_notifications_auto_download_5m">Si inferior a 5 MB</string>
<string name="settings_notifications_auto_download_10m">Si inferior a 10 MB</string>
<string name="settings_notifications_auto_download_50m">Si inferior a 50 MB</string>
<string name="settings_notifications_auto_delete_title">Eliminar notificacions</string>
<string name="settings_notifications_auto_delete_summary_never">No eliminar mai les notificacions automàticament</string>
<string name="settings_notifications_auto_delete_summary_one_day">Eliminar les notificacions automàticament al cap d\'un dia</string>
<string name="settings_notifications_auto_delete_summary_three_days">Eliminar automàticament les notificacions al cap de tres dies</string>
<string name="settings_notifications_auto_delete_summary_one_month">Eliminar automàticament les notificacions al cap d\'un mes</string>
<string name="settings_notifications_auto_delete_summary_three_months">Eliminar automàticament les notificacions al cap de 3 mesos</string>
<string name="settings_notifications_auto_delete_three_months">Al cap de 3 mesos</string>
<string name="settings_general_header">General</string>
<string name="settings_general_users_summary">Afegir/eliminar usuaris a temes protegits</string>
<string name="settings_general_users_prefs_user_used_by_one">Usat pel tema %1$s</string>
<string name="settings_general_users_prefs_user_used_by_many">Usat pels temes %1$s</string>
<string name="settings_general_dark_mode_entry_dark">Mode fosc</string>
<string name="settings_backup_restore_header">Còpia de seguretat &amp; Restauració</string>
<string name="settings_backup_restore_backup_title">Fer còpia de seguretat en arxiu</string>
<string name="settings_backup_restore_backup_entry_everything">Tot</string>
<string name="settings_backup_restore_backup_entry_everything_no_users">Tot, excepte usuaris</string>
<string name="settings_backup_restore_backup_entry_settings_only">Només configuració</string>
<string name="settings_backup_restore_backup_successful">Còpia de seguretat creada</string>
<string name="settings_backup_restore_backup_failed">Còpia de seguretat fallida: %1$s</string>
<string name="settings_backup_restore_restore_successful">Recuperació exitosa</string>
<string name="settings_advanced_broadcast_summary_disabled">Les aplicacions no poden rebre notificacions com a missatges</string>
<string name="settings_advanced_record_logs_title">Gravar registres</string>
<string name="settings_advanced_export_logs_scrub_dialog_text">Aquest temes/noms de host han estat reemplaçats per noms de fruites, per tal que els puguis compartir tranquil·lament:
\n
\n%1$s
\n
\nLes contrasenyes s\'han descartat, però no es mostren.</string>
<string name="settings_advanced_export_logs_scrub_dialog_empty">Cap tema/nom de host ha estat censurat. Potser no tens cap subscripció\?</string>
<string name="settings_advanced_export_logs_scrub_dialog_button_ok">D\'acord</string>
<string name="settings_about_version_copied_to_clipboard_message">Copiat al porta-retalls</string>
<string name="detail_settings_appearance_header">Apariència</string>
<string name="detail_settings_appearance_icon_set_summary">Triar una icona per mostrar a les notificacions</string>
<string name="detail_settings_appearance_icon_remove_summary">Icona mostrada a notificacions d\'aquest tema</string>
<string name="user_dialog_password_hint_add">Contrasenya</string>
<string name="user_dialog_password_hint_edit">Contrasenya (no canvia si es deixa en blanc)</string>
<string name="user_dialog_button_add">Afegir usuari</string>
<string name="settings_notifications_auto_download_summary_never">Mai descarregar automàticament els adjunts</string>
<string name="settings_advanced_connection_protocol_entry_jsonhttp">Flux JSON a través d\'HTTP</string>
<string name="settings_advanced_connection_protocol_entry_ws">WebSockets</string>
<string name="settings_about_header">Quant a</string>
<string name="settings_advanced_export_logs_entry_upload_original">Carregar i copiar enllaç</string>
<string name="user_dialog_button_delete">Eliminar usuari</string>
<string name="user_dialog_button_save">Guardar</string>
</resources>

View file

@ -1,346 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="main_menu_report_bug_title">Nahlásit chybu</string>
<string name="detail_how_to_link">Podrobné pokyny jsou k dispozici na stránce ntfy.sh a v dokumentaci.</string>
<string name="detail_test_message_error">Nelze odeslat zprávu: %1$s</string>
<string name="channel_subscriber_service_name">Služba odběru</string>
<string name="channel_subscriber_notification_title">Naslouchání příchozím oznámením</string>
<string name="channel_subscriber_notification_instant_text">Přihlášeno k odběru témat pro okamžité doručení</string>
<string name="channel_subscriber_notification_instant_text_one">Přihlášeno k odběru jednoho tématu okamžitého doručení</string>
<string name="channel_subscriber_notification_instant_text_two">Přihlášeno k odběru dvou témat okamžitého doručení</string>
<string name="channel_subscriber_notification_instant_text_three">Přihlášeno k odběru tří témat okamžitého doručení</string>
<string name="channel_subscriber_notification_instant_text_more">Přihlášeno k odběru %1$d témat okamžitého doručení</string>
<string name="channel_subscriber_notification_noinstant_text">Přihlášeno k odběru témat</string>
<string name="channel_subscriber_notification_noinstant_text_one">Odběr jednoho tématu</string>
<string name="channel_subscriber_notification_noinstant_text_two">Odběr dvou témat</string>
<string name="channel_subscriber_notification_noinstant_text_four">Odběr čtyř témat</string>
<string name="channel_subscriber_notification_noinstant_text_more">Odběr %1$d témat</string>
<string name="refresh_message_result">%1$d oznámení přijato</string>
<string name="refresh_message_no_results">Vše je aktuální</string>
<string name="refresh_message_error">Nepodařilo se obnovit %1$d odběrů
\n
\n%2$s</string>
<string name="main_action_bar_title">Odebíraná témata</string>
<string name="main_menu_notifications_enabled">Oznámení zapnuta</string>
<string name="channel_notifications_default_name">Výchozí priorita</string>
<string name="channel_notifications_high_name">Vysoká priorita</string>
<string name="main_menu_notifications_disabled_until">Oznámení ztlumena do %1$s</string>
<string name="main_menu_settings_title">Nastavení</string>
<string name="main_menu_docs_title">Přečíst dokumentaci</string>
<string name="main_menu_rate_title">Ohodnotit aplikaci ⭐</string>
<string name="main_action_mode_menu_unsubscribe">Odhlásit odběr</string>
<string name="main_action_mode_delete_dialog_permanently_delete">Odstranit natrvalo</string>
<string name="main_action_mode_delete_dialog_cancel">Zrušit</string>
<string name="main_item_status_text_one">%1$d oznámení</string>
<string name="main_item_status_text_not_one">%1$d oznámení</string>
<string name="main_item_status_reconnecting">obnovování spojení …</string>
<string name="main_item_status_unified_push">%1$s (UnifiedPush)</string>
<string name="main_item_date_yesterday">včera</string>
<string name="main_add_button_description">Přidat odběr</string>
<string name="main_no_subscriptions_text">Vypadá to, že ještě nemáte žádný odběr.</string>
<string name="main_how_to_link">Podrobné pokyny jsou k dispozici na stránce ntfy.sh a v dokumentaci.</string>
<string name="main_unified_push_toast">Tento odběr spravuje %1$s prostřednictvím UnifiedPush</string>
<string name="main_banner_battery_text">Optimalizace baterie by měla být pro aplikaci vypnutá, aby se předešlo problémům s doručováním oznámení.</string>
<string name="main_banner_battery_button_remind_later">Zeptat se později</string>
<string name="main_banner_websocket_button_remind_later">Zeptat se později</string>
<string name="main_banner_websocket_button_dismiss">Zavřít</string>
<string name="add_dialog_topic_name_hint">Název tématu, např. phils_alerts</string>
<string name="add_dialog_use_another_server_description">Zadejte URL služby a přihlaste se k odběru témat z jiných serverů.</string>
<string name="add_dialog_instant_delivery">Okamžité doručení v režimu spánku</string>
<string name="add_dialog_instant_delivery_description">Zajišťuje okamžité doručení zpráv, i když je zařízení neaktivní.</string>
<string name="add_dialog_foreground_description">Okamžité doručení je vždy zapnuto pro jiné hostitele než %1$s .</string>
<string name="add_dialog_button_cancel">Zrušit</string>
<string name="add_dialog_button_subscribe">Přihlásit odběr</string>
<string name="add_dialog_button_back">Zpět</string>
<string name="add_dialog_error_connection_failed">Připojení se nezdařilo: %1$s</string>
<string name="add_dialog_login_title">Vyžadováno přihlášení</string>
<string name="add_dialog_login_description">Toto téma vyžaduje přihlášení. Zadejte prosím uživatelské jméno a heslo.</string>
<string name="add_dialog_login_username_hint">Uživatelské jméno</string>
<string name="add_dialog_login_password_hint">Heslo</string>
<string name="add_dialog_login_error_not_authorized">Přihlášení se nezdařilo. Uživatel %1$s není autorizován.</string>
<string name="detail_no_notifications_text">K tomuto tématu jste zatím neobdrželi žádné oznámení.</string>
<string name="detail_how_to_intro">Pro odeslání oznámení k tomuto tématu, jednoduše odešlete PUT nebo POST dotaz na URL tématu.</string>
<string name="detail_how_to_example">Příklad (použití curl):<br/><tt>$ curl -d \"Hi\" %1$s</tt></string>
<string name="detail_clear_dialog_message">Smazat všechna oznámení v tomto tématu\?</string>
<string name="detail_clear_dialog_permanently_delete">Odstranit natrvalo</string>
<string name="detail_delete_dialog_message">Odhlásit se z tohoto tématu a smazat všechna přijatá oznámení\?</string>
<string name="detail_delete_dialog_permanently_delete">Odstranit natrvalo</string>
<string name="detail_delete_dialog_cancel">Zrušit</string>
<string name="detail_test_title">Test: Pokud chcete, můžete nastavit název.</string>
<string name="detail_test_message_error_unauthorized_anon">Nelze odeslat zprávu: Anonymní publikování není povoleno.</string>
<string name="detail_test_message_error_unauthorized_user">Nelze odeslat zprávu: Uživatel \"%1$s\" není autorizován.</string>
<string name="detail_test_message_error_too_large">Nelze odeslat zprávu: Příloha je příliš velká.</string>
<string name="detail_copied_to_clipboard_message">Zkopírováno do schránky</string>
<string name="detail_instant_delivery_enabled">Okamžité doručení zapnuto</string>
<string name="detail_instant_delivery_disabled">Okamžité doručení vypnuto</string>
<string name="detail_deep_link_subscribed_toast_message">Přihlášeno k odběru tématu %1$s</string>
<string name="detail_item_tags">Značky: %1$s</string>
<string name="detail_item_snack_deleted">Oznámení odstraněno</string>
<string name="detail_item_snack_undo">Zpět</string>
<string name="detail_item_menu_open">Otevřít soubor</string>
<string name="detail_item_menu_download">Stáhnout soubor</string>
<string name="detail_item_menu_cancel">Zrušit stahování</string>
<string name="detail_item_menu_save_file">Uložit soubor</string>
<string name="detail_item_menu_copy_url">Zkopírovat URL</string>
<string name="detail_item_menu_copy_contents">Kopírovat oznámení</string>
<string name="detail_item_menu_copy_contents_copied">Oznámení zkopírováno do schránky</string>
<string name="detail_item_saved_successfully">Uloženo jako \"%1$s\" do složky \"Stažené\"</string>
<string name="detail_item_cannot_open">Nelze otevřít přílohu: %1$s</string>
<string name="detail_item_cannot_open_not_found">Nelze otevřít přílohu: Soubor mohl být smazán nebo jej nemůže otevřít žádná nainstalovaná aplikace.</string>
<string name="detail_item_cannot_open_url">Nelze otevřít URL: %1$s</string>
<string name="detail_item_cannot_save">Nelze uložit přílohu: %1$s</string>
<string name="detail_item_cannot_delete">Nelze smazat přílohu: %1$s</string>
<string name="detail_item_download_failed">Nepodařilo se stáhnout přílohu: %1$s</string>
<string name="detail_item_download_info_not_downloaded_expires_x">nebylo staženo, platnost vypršela %1$s</string>
<string name="detail_item_download_info_deleted">smazáno</string>
<string name="detail_item_download_info_deleted_expired">smazáno, platnost odkazu vypršela</string>
<string name="detail_item_download_info_deleted_expires_x">smazáno, platnost odkazu vypršela %1$s</string>
<string name="detail_item_download_info_download_failed">stažení se nezdařilo</string>
<string name="detail_menu_notifications_enabled">Oznámení zapnuta</string>
<string name="detail_menu_notifications_disabled_forever">Oznámení ztlumena</string>
<string name="detail_menu_notifications_disabled_until">Oznámení ztlumena do %1$s</string>
<string name="detail_menu_enable_instant">Povolit okamžité doručení</string>
<string name="detail_menu_disable_instant">Vypnout okamžité doručení</string>
<string name="detail_menu_settings">Nastavení odběru</string>
<string name="detail_menu_unsubscribe">Odhlásit se z odběru</string>
<string name="detail_action_mode_menu_copy">Kopírovat</string>
<string name="detail_action_mode_menu_delete">Smazat</string>
<string name="detail_action_mode_delete_dialog_message">Trvale odstranit vybraná oznámení\?</string>
<string name="detail_action_mode_delete_dialog_permanently_delete">Odstranit natrvalo</string>
<string name="share_menu_send">Sdílet</string>
<string name="share_content_title">Náhled zprávy</string>
<string name="share_content_text_hint">Přidat obsah ke sdílení zde</string>
<string name="share_content_image_error">Nelze načíst obrázek: %1$s</string>
<string name="share_content_file_error">Nelze přečíst informace o souboru: %1$s</string>
<string name="share_content_image_text">Byl vám nasdílen obrázek</string>
<string name="share_topic_title">Sdílet s</string>
<string name="share_suggested_topics">Navrhovaná témata</string>
<string name="share_successful">Zpráva zveřejněna</string>
<string name="notification_dialog_title">Ztlumit oznámení</string>
<string name="notification_dialog_cancel">Zrušit</string>
<string name="notification_dialog_save">Uložit</string>
<string name="notification_dialog_enabled_toast_message">Oznámení byla obnovena</string>
<string name="notification_dialog_muted_forever_toast_message">Oznámení ztlumena</string>
<string name="notification_dialog_show_all">Zobrazit všechna oznámení</string>
<string name="notification_dialog_30min">30 minut</string>
<string name="notification_dialog_1h">1 hodina</string>
<string name="notification_dialog_2h">2 hodiny</string>
<string name="notification_dialog_8h">8 hodin</string>
<string name="notification_dialog_forever">Do obnovení</string>
<string name="notification_popup_action_cancel">Zrušit</string>
<string name="notification_popup_file">%1$s
\nSoubor: %2$s</string>
<string name="notification_popup_file_downloading">Stahování %1$s, %2$d%%
\n%3$s</string>
<string name="notification_popup_file_download_successful">%1$s
\nSoubor: %2$s, staženo</string>
<string name="notification_popup_file_download_failed">%1$s
\nSoubor: %2$s, stažení se nezdařilo</string>
<string name="notification_popup_user_action_failed">%1$s selhalo: %2$s</string>
<string name="settings_title">Nastavení</string>
<string name="settings_notifications_header">Oznámení</string>
<string name="settings_notifications_muted_until_title">Ztlumit oznámení</string>
<string name="settings_notifications_muted_until_show_all">Zobrazení všech upozornění</string>
<string name="settings_notifications_muted_until_x">Oznámení ztlumena do %1$s</string>
<string name="settings_notifications_min_priority_title">Nejnižší priorita</string>
<string name="settings_notifications_min_priority_low">Nízká priorita a vyšší</string>
<string name="settings_notifications_min_priority_max">Pouze nejvyšší priorita</string>
<string name="settings_notifications_priority_min">nejnižší</string>
<string name="settings_notifications_priority_low">nízká</string>
<string name="settings_notifications_priority_default">výchozí</string>
<string name="settings_notifications_priority_high">vysoká</string>
<string name="settings_notifications_priority_max">nejvyšší</string>
<string name="settings_notifications_channel_prefs_title">Nastavení kanálu</string>
<string name="settings_notifications_channel_prefs_summary">Vlastní režim Nerušit (DND), zvuky atd.</string>
<string name="settings_notifications_auto_download_summary_never">Nikdy nestahovat přílohy automaticky</string>
<string name="settings_notifications_auto_download_summary_smaller_than_x">Automaticky stahovat přílohy až do velikosti %1$s</string>
<string name="settings_notifications_auto_download_never">Nikdy nic automaticky nestahovat</string>
<string name="settings_notifications_auto_download_always">Automaticky stahovat vše</string>
<string name="settings_notifications_auto_download_1m">Pokud je menší než 1 MB</string>
<string name="settings_notifications_auto_download_10m">Pokud je menší než 10 MB</string>
<string name="settings_notifications_auto_delete_title">Odstranit oznámení</string>
<string name="settings_notifications_auto_delete_summary_never">Nikdy automaticky neodstraňovat oznámení</string>
<string name="settings_notifications_auto_delete_summary_one_day">Automaticky mazat oznámení po jednom dni</string>
<string name="settings_notifications_auto_delete_summary_three_days">Automaticky mazat oznámení po 3 dnech</string>
<string name="settings_notifications_auto_delete_summary_one_week">Automaticky mazat oznámení po jednom týdnu</string>
<string name="settings_notifications_auto_delete_summary_one_month">Automaticky mazat oznámení po jednom měsíci</string>
<string name="settings_notifications_auto_delete_never">Nikdy</string>
<string name="settings_notifications_auto_delete_one_day">Po jednom dni</string>
<string name="settings_notifications_auto_delete_three_days">Po 3 dnech</string>
<string name="settings_notifications_auto_delete_one_week">Po jednom týdnu</string>
<string name="settings_notifications_auto_delete_one_month">Po jednom měsíci</string>
<string name="settings_notifications_auto_delete_three_months">Po 3 měsících</string>
<string name="settings_general_header">Obecné</string>
<string name="settings_general_default_base_url_title">Výchozí server</string>
<string name="settings_general_default_base_url_message">Zadejte kořenovou adresu URL svého serveru, jako výchozí při přihlašování k odběru nových témat nebo sdílení témat.</string>
<string name="settings_general_users_prefs_user_add">Přidat uživatele</string>
<string name="settings_general_users_prefs_user_add_summary">Vytvořit nového uživatele pro nový server</string>
<string name="settings_general_dark_mode_title">Tmavý režim</string>
<string name="settings_general_dark_mode_summary_system">Používat výchozí nastavení systému</string>
<string name="settings_general_dark_mode_summary_light">Světlý režim zapnutý</string>
<string name="settings_general_dark_mode_summary_dark">Tmavý režim zapnut. Jste upír\?</string>
<string name="settings_general_dark_mode_entry_system">Použít výchozí nastavení systému</string>
<string name="settings_general_dark_mode_entry_light">Světlý režim</string>
<string name="settings_general_dark_mode_entry_dark">Tmavý režim</string>
<string name="settings_backup_restore_header">Zálohování a obnovení</string>
<string name="settings_backup_restore_backup_title">Zálohovat do souboru</string>
<string name="settings_backup_restore_backup_summary">Export konfigurace, oznámení a uživatelů</string>
<string name="settings_backup_restore_backup_entry_everything">Všechno</string>
<string name="settings_backup_restore_backup_entry_settings_only">Pouze nastavení</string>
<string name="settings_backup_restore_backup_successful">Záloha vytvořena</string>
<string name="settings_backup_restore_backup_failed">Zálohování se nezdařilo: %1$s</string>
<string name="settings_backup_restore_restore_title">Obnovit ze souboru</string>
<string name="settings_backup_restore_restore_summary">Import konfigurace, oznámení a uživatelů</string>
<string name="settings_backup_restore_restore_successful">Obnova byla úspěšná</string>
<string name="settings_backup_restore_restore_failed">Obnovení se nezdařilo: %1$s</string>
<string name="settings_advanced_broadcast_title">Rozesílat zprávy</string>
<string name="settings_advanced_record_logs_title">Záznamy protokolů</string>
<string name="settings_advanced_record_logs_summary_enabled">Protokolování (až 1 000 záznamů) do zařízení …</string>
<string name="settings_advanced_export_logs_title">Kopírování/odesílání protokolů</string>
<string name="settings_advanced_export_logs_summary">Zkopírujte protokoly do schránky nebo je nahrajte na nopaste.net (patří autorovi ntfy). Názvy hostitelů a témata mohou být cenzurovány, oznámení nikoli.</string>
<string name="settings_advanced_export_logs_entry_upload_original">Nahrát a zkopírovat odkaz</string>
<string name="settings_advanced_export_logs_entry_upload_scrubbed">Nahrát a zkopírovat odkaz (cenzurované)</string>
<string name="settings_advanced_export_logs_copied_logs">Protokoly zkopírované do schránky</string>
<string name="settings_advanced_export_logs_uploading">Nahrávání protokolu …</string>
<string name="settings_advanced_export_logs_copied_url">Protokoly nahrané a adresa URL zkopírována</string>
<string name="settings_advanced_export_logs_error_uploading">Nelze nahrát protokoly: %1$s</string>
<string name="settings_advanced_export_logs_scrub_dialog_text">Tato témata/názvy hostitelů byly nahrazeny názvy ovoce, takže můžete protokol bez obav sdílet:
\n
\n%1$s
\n
\nHesla jsou vymazána, ale nejsou zde uvedena.</string>
<string name="settings_advanced_export_logs_scrub_dialog_empty">Žádná témata/názvy hostitelů nebyly redigovány. Možná nemáte žádné odběry\?</string>
<string name="settings_advanced_clear_logs_summary">Odstranit dříve zaznamenané protokoly a začít znovu</string>
<string name="settings_advanced_clear_logs_deleted_toast">Protokoly odstraněny</string>
<string name="settings_advanced_connection_protocol_title">Protokol připojení</string>
<string name="settings_advanced_connection_protocol_summary_ws">Pro připojení k serveru použít WebSockets. Jedná se o doporučenou metodu, která však může vyžadovat další konfiguraci v proxy serveru.</string>
<string name="settings_advanced_connection_protocol_entry_ws">WebSockets</string>
<string name="settings_about_header">O programu</string>
<string name="settings_about_version_title">Verze</string>
<string name="settings_about_version_format">ntfy %1$s (%2$s)</string>
<string name="settings_about_version_copied_to_clipboard_message">Zkopírováno do schránky</string>
<string name="user_dialog_title_add">Přidat uživatele</string>
<string name="user_dialog_description_edit">Uživatelské jméno a heslo vybraného uživatele můžete upravit nebo odstranit.</string>
<string name="user_dialog_base_url_hint">URL služby</string>
<string name="user_dialog_username_hint">Uživatelské jméno</string>
<string name="user_dialog_password_hint_add">Heslo</string>
<string name="user_dialog_password_hint_edit">Heslo (nezměněno, pokud zůstane prázdné)</string>
<string name="user_dialog_button_add">Přidat uživatele</string>
<string name="user_dialog_button_cancel">Zrušit</string>
<string name="user_dialog_button_delete">Odstranit uživatele</string>
<string name="user_dialog_button_save">Uložit</string>
<string name="refresh_message_error_one">Nepodařilo se obnovit odběr: %1$s</string>
<string name="channel_subscriber_notification_instant_text_four">Přihlášeno k odběru čtyř témat okamžitého doručení</string>
<string name="channel_subscriber_notification_noinstant_text_three">Odběr tří témat</string>
<string name="main_menu_notifications_disabled_forever">Oznámení ztlumena</string>
<string name="main_how_to_intro">Kliknutím na tlačítko + vytvoříte téma nebo se k němu přihlásíte. Poté obdržíte na svém zařízení oznámení při odesílání zpráv prostřednictvím PUT nebo POST.</string>
<string name="main_banner_battery_button_dismiss">Zavřít</string>
<string name="main_banner_battery_button_fix_now">Opravit nyní</string>
<string name="add_dialog_title">Přihlásit se k odběru tématu</string>
<string name="add_dialog_button_login">Přihlásit se</string>
<string name="main_action_mode_delete_dialog_message">Odhlásit odběr vybraných témat a trvale odstranit všechna oznámení\?</string>
<string name="add_dialog_description_below">Témata nemusí být chráněna heslem, proto zvolte název, který je obtížné uhodnout. Jakmile se přihlásíte k odběru, můžete posílat oznámení pomocí PUT/POST.</string>
<string name="add_dialog_use_another_server">Použít jiný server</string>
<string name="add_dialog_login_new_user">Nový uživatel</string>
<string name="detail_clear_dialog_cancel">Zrušit</string>
<string name="detail_item_menu_copy_url_copied">URL zkopírováno do schránky</string>
<string name="detail_item_download_info_download_failed_expired">stažení se nezdařilo, platnost odkazu vypršela</string>
<string name="detail_item_cannot_download">Nelze otevřít ani stáhnout přílohu. Platnost odkazu vypršela a žádný místní soubor nebyl nalezen.</string>
<string name="detail_item_download_info_not_downloaded_expired">nebylo staženo, platnost odkazu vypršela</string>
<string name="detail_item_download_info_download_failed_expires_x">stažení se nezdařilo, platnost odkazu vypršela %1$s</string>
<string name="detail_test_message">Toto je testovací oznámení z aplikace ntfy pro Android. Má prioritu na úrovni %1$d. Pokud odešlete jiné, může vypadat jinak.</string>
<string name="detail_item_menu_delete">Smazat soubor</string>
<string name="detail_item_download_info_not_downloaded">nebylo staženo</string>
<string name="detail_item_download_info_downloading_x_percent">%1$d%% staženo</string>
<string name="detail_menu_test">Odeslat testovací oznámení</string>
<string name="detail_menu_clear">Vymazat všechna oznámení</string>
<string name="settings_notifications_muted_until_forever">Oznámení ztlumena až do obnovení</string>
<string name="channel_notifications_low_name">Malá priorita</string>
<string name="channel_notifications_min_name">Nejnižší priorita</string>
<string name="channel_notifications_max_name">Nejvyšší priorita</string>
<string name="detail_menu_copy_url">Kopírovat adresu tématu</string>
<string name="detail_settings_title">Nastavení odběru</string>
<string name="detail_action_mode_delete_dialog_cancel">Zrušit</string>
<string name="share_title">Sdílet</string>
<string name="settings_notifications_min_priority_min">Jakákoli priorita</string>
<string name="settings_notifications_auto_download_summary_always">Automatické stažení všech příloh</string>
<string name="share_content_file_text">Byl vám nasdílen soubor</string>
<string name="notification_popup_action_download">Stáhnout</string>
<string name="notification_dialog_tomorrow">Do zítra</string>
<string name="notification_popup_action_open">Otevřít</string>
<string name="notification_dialog_muted_until_toast_message">Oznámení ztlumena do %1$s</string>
<string name="notification_popup_action_browse">Procházet</string>
<string name="settings_notifications_min_priority_summary_max">Zobrazit oznámení, pokud je priorita 5 (nevyšší)</string>
<string name="settings_notifications_min_priority_summary_any">Zobrazení všech oznámení</string>
<string name="settings_notifications_min_priority_summary_x_or_higher">Zobrazit oznámení, pokud je priorita %1$d (%2$s) nebo vyšší</string>
<string name="settings_notifications_auto_download_50m">Pokud je menší než 50 MB</string>
<string name="settings_notifications_min_priority_default">Výchozí priorita a vyšší</string>
<string name="settings_notifications_min_priority_high">Vysoká priorita a vyšší</string>
<string name="settings_notifications_auto_download_100k">Pokud je menší než 100 kB</string>
<string name="settings_notifications_auto_download_5m">Pokud je menší než 5 B</string>
<string name="settings_notifications_auto_download_title">Stáhnout přílohy</string>
<string name="settings_notifications_auto_download_500k">Pokud je menší než 500 kB</string>
<string name="settings_notifications_auto_delete_summary_three_months">Automaticky mazat oznámení po 3 měsících</string>
<string name="settings_general_users_prefs_user_not_used">Nepoužívá se u žádných témat</string>
<string name="settings_general_users_prefs_user_add_title">Přidat nového uživatele</string>
<string name="settings_general_default_base_url_default_summary">%1$s (výchozí)</string>
<string name="settings_general_users_title">Správa uživatelů</string>
<string name="settings_general_users_summary">Přidávání/odebírání uživatelů pro chráněná témata</string>
<string name="settings_general_users_prefs_user_used_by_many">Použito v tématech %1$s</string>
<string name="settings_general_users_prefs_title">Uživatelé</string>
<string name="settings_general_users_prefs_user_used_by_one">Použito v tématu %1$s</string>
<string name="settings_advanced_broadcast_summary_disabled">Aplikace nemohou přijímat oznámení jako vysílání</string>
<string name="settings_advanced_clear_logs_title">Vymazat protokoly</string>
<string name="user_dialog_title_edit">Upravit uživatele</string>
<string name="settings_backup_restore_backup_entry_everything_no_users">Všechno kromě uživatelů</string>
<string name="settings_advanced_header">Pokročilé</string>
<string name="settings_advanced_broadcast_summary_enabled">Aplikace mohou přijímat příchozí oznámení jako vysílání</string>
<string name="settings_advanced_record_logs_summary_disabled">Zapněte protokolování, abyste mohli později sdílet protokoly a diagnostikovat problémy.</string>
<string name="settings_advanced_export_logs_entry_copy_original">Kopírovat do schránky</string>
<string name="settings_advanced_export_logs_entry_copy_scrubbed">Kopírovat do schránky (cenzurované)</string>
<string name="settings_advanced_export_logs_scrub_dialog_button_ok">OK</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Pro připojení k serveru použít JSON přes protokol HTTP. Tato metoda je ověřená v praxi, ale může spotřebovávat více baterie.</string>
<string name="user_dialog_description_add">Zde můžete přidat uživatele. Tento uživatel bude používán ve všech tématech pro daný server.</string>
<string name="settings_advanced_connection_protocol_entry_jsonhttp">JSON přes HTTP</string>
<string name="channel_subscriber_notification_instant_text_five">Přihlášeno k odběru pěti témat okamžitého doručení</string>
<string name="channel_subscriber_notification_noinstant_text_five">Odběr pěti témat</string>
<string name="channel_subscriber_notification_noinstant_text_six">Odběr šesti témat</string>
<string name="detail_settings_notifications_instant_summary_on">Oznámení jsou doručena okamžitě. Vyžaduje službu v popředí a spotřebovává více baterie.</string>
<string name="detail_settings_appearance_header">Vzhled</string>
<string name="detail_settings_appearance_icon_set_title">Ikona odběru</string>
<string name="detail_settings_appearance_icon_set_summary">Nastavení ikony, která se má zobrazovat v oznámeních</string>
<string name="detail_settings_appearance_icon_remove_title">Ikona odběru (klepnutím ji odeberete)</string>
<string name="detail_settings_appearance_icon_remove_summary">Ikona k tomuto tématu zobrazená v oznámeních</string>
<string name="detail_settings_appearance_icon_error_saving">Nelze uložit ikonu: %1$s</string>
<string name="detail_settings_global_setting_title">Použít globální nastavení</string>
<string name="detail_settings_global_setting_suffix">používá se globální nastavení</string>
<string name="channel_subscriber_notification_instant_text_six">Přihlášeno k odběru šesti témat okamžitého doručení</string>
<string name="detail_settings_notifications_instant_summary_off">Oznámení jsou doručena pomocí služby Firebase. Doručování může být zpožděné, ale spotřebovává méně baterie.</string>
<string name="detail_settings_notifications_instant_title">Okamžité doručení</string>
<string name="detail_settings_appearance_display_name_title">Zobrazit název</string>
<string name="detail_settings_appearance_display_name_message">Nastavit vlastní zobrazovaný název pro tento odběr. Pro výchozí hodnotu (%1$s) ponechte prázdné.</string>
<string name="detail_settings_appearance_display_name_default_summary">%1$s (výchozí)</string>
<string name="detail_settings_about_header">O aplikaci</string>
<string name="detail_settings_about_topic_url_title">URL tématu</string>
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">Zkopírováno do schránky</string>
<string name="add_dialog_base_urls_dropdown_clear">Vymazat URL služby</string>
<string name="main_banner_websocket_button_enable_now">Povolit nyní</string>
<string name="main_banner_websocket_text">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 <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">další konfiguraci v proxy serveru</a>. Metodu připojení lze přepnout v Nastavení.</string>
<string name="add_dialog_base_urls_dropdown_choose">Zvolit URL služby</string>
<string name="main_menu_donate_title">Přispět 💸</string>
<string name="detail_item_cannot_open_apk">Aplikace již nelze nainstalovat. Místo toho stahujte přes prohlížeč. Podrobnosti naleznete v issue #531.</string>
<string name="channel_notifications_group_default_name">Výchozí</string>
<string name="settings_notifications_insistent_max_priority_summary_disabled">Upozornění s nejvyšší prioritou pouze jednou</string>
<string name="detail_settings_notifications_dedicated_channels_summary_on">Používání vlastních nastavení pro tento odběr</string>
<string name="detail_settings_notifications_open_channels_title">Konfigurace nastavení oznámení</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_enabled">Stále upozorňovat</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_disabled">Upozornit pouze jednou</string>
<string name="detail_settings_notifications_dedicated_channels_title">Vlastní nastavení oznámení</string>
<string name="settings_notifications_insistent_max_priority_title">Zachovat upozornění na nejvyšší prioritu</string>
<string name="settings_notifications_insistent_max_priority_summary_enabled">Oznámení s maximální prioritou nepřetržitě upozorňují až do odvolání</string>
<string name="detail_settings_notifications_dedicated_channels_summary_off">Použití výchozího nastavení (zvuky, vlastní nastavení funkce Nerušit, atd.)</string>
<string name="detail_settings_notifications_open_channels_summary">Vlastní nastavení funkce Nerušit (DND), zvuky, atd.</string>
<string name="settings_advanced_unifiedpush_summary_enabled">ntfy bude fungovat jako distributor UnifiedPush</string>
<string name="settings_advanced_unifiedpush_title">Povolit UnifiedPush</string>
<string name="settings_advanced_unifiedpush_summary_disabled">ntfy nebude fungovat jako distributor UnifiedPush</string>
</resources>

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="channel_notifications_high_name">Blaenoriaeth uchel</string>
<string name="channel_notifications_min_name">Blaenoriaeth lleiaf</string>
<string name="channel_notifications_low_name">Blaenoriaeth isel</string>
</resources>

View file

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="channel_subscriber_notification_instant_text">Abonnerer på emner med øjeblikkelig levering</string>
<string name="channel_notifications_max_name">Maks. prioritet</string>
<string name="channel_subscriber_notification_instant_text_two">Abonnerer på to emner om øjeblikkelig levering</string>
<string name="channel_notifications_group_default_name">standard</string>
<string name="channel_subscriber_notification_instant_text_six">Abonnerer på seks emner med øjeblikkelig levering</string>
<string name="channel_subscriber_notification_instant_text_three">Abonnerer på tre emner med øjeblikkelig levering</string>
<string name="channel_subscriber_service_name">Abonnementsservice</string>
<string name="channel_subscriber_notification_instant_text_five">Abonnerer på fem emner med øjeblikkelig levering</string>
<string name="channel_notifications_default_name">Standardprioritet</string>
<string name="channel_notifications_min_name">Minimum prioritet</string>
<string name="channel_subscriber_notification_instant_text_more">Abonnerer på %1$d emner med øjeblikkelig levering</string>
<string name="channel_notifications_low_name">Lav prioritet</string>
<string name="channel_subscriber_notification_noinstant_text">Abonnerer på emner</string>
<string name="channel_subscriber_notification_title">Lytter efter indgående notifikationer</string>
<string name="channel_subscriber_notification_instant_text_one">Abonnerer på et emne med øjeblikkelig levering</string>
<string name="channel_subscriber_notification_instant_text_four">Abonnerer på fire emner med øjeblikkelig levering</string>
<string name="channel_notifications_high_name">Høj prioritet</string>
</resources>

View file

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="channel_notifications_low_name">Niedrige Priorität</string>
<string name="channel_notifications_default_name">Normale Priorität</string>
<string name="channel_notifications_high_name">Hohe Priorität</string>
<string name="channel_notifications_max_name">Höchste Priorität</string>
<string name="channel_notifications_low_name">Benachrichtigungen (niedrige Priorität)</string>
<string name="channel_notifications_default_name">Benachrichtigungen (normale Priorität)</string>
<string name="channel_notifications_high_name">Benachrichtigungen (hohe Priorität)</string>
<string name="channel_notifications_max_name">Benachrichtigungen (max. Priorität)</string>
<string name="channel_subscriber_service_name">Abo Service</string>
<string name="channel_notifications_min_name">Min. Priorität</string>
<string name="channel_notifications_min_name">Benachrichtigungen (min. Priorität)</string>
<string name="channel_subscriber_notification_title">Warte auf Benachrichtigungen</string>
<string name="channel_subscriber_notification_instant_text_one">Ein Sofortnachrichten-Thema abonniert</string>
<string name="channel_subscriber_notification_instant_text_two">Zwei Sofortnachrichten-Themen abonniert</string>
@ -26,7 +26,7 @@
<string name="refresh_message_error_one">Abo konnte nicht aktualisiert werden: %1$s</string>
<string name="main_action_bar_title">Abonnierte Themen</string>
<string name="main_menu_notifications_enabled">Benachrichtigungen aktiviert</string>
<string name="main_menu_notifications_disabled_forever">Benachrichtigungen stummgeschaltet</string>
<string name="main_menu_notifications_disabled_forever">Benachrichtigungen pausiert</string>
<string name="channel_subscriber_notification_instant_text">Sofortnachrichten-Themen abonniert</string>
<string name="main_menu_report_bug_title">Fehler melden</string>
<string name="main_menu_docs_title">Dokumentation lesen</string>
@ -45,7 +45,8 @@
<string name="main_unified_push_toast">Dieses Abo wird von %1$s per UnifiedPush verwaltet</string>
<string name="main_banner_battery_text">Batterieoptimierungen sollten für die App deaktiviert sein, um Zustellungsprobleme bei Benachrichtigungen zu vermeiden.</string>
<string name="main_banner_battery_button_fix_now">Jetzt beheben</string>
<string name="main_banner_websocket_button_remind_later">Später fragen</string>
<string name="main_banner_json_stream_button_remind_later">Später fragen</string>
<string name="main_banner_json_stream_button_learn_more">Mehr erfahren</string>
<string name="add_dialog_title">Thema abonnieren</string>
<string name="add_dialog_description_below">Themen sind evtl. nicht kennwort-geschützt, also wähle einen schwer zu erratenden Namen. Nach dem Abonnieren kannst Du Benachrichtigungen POSTen/PUTen.</string>
<string name="add_dialog_topic_name_hint">Themenname, z.B. phils_alerts</string>
@ -56,7 +57,7 @@
<string name="add_dialog_instant_delivery_description">Stellt sicher, dass Benachrichtigungen sofort zugestellt werden, auch wenn das Gerät im Schlafmodus ist.</string>
<string name="add_dialog_button_cancel">Abbrechen</string>
<string name="main_banner_battery_button_dismiss">Verwerfen</string>
<string name="main_banner_websocket_button_dismiss">Verwerfen</string>
<string name="main_banner_json_stream_button_dismiss">Verwerfen</string>
<string name="add_dialog_login_title">Anmeldung erforderlich</string>
<string name="add_dialog_login_description">Dieses Thema benötigt eine Anmeldung. Bitte gib Benutzernamen und Kennwort ein.</string>
<string name="add_dialog_login_password_hint">Kennwort</string>
@ -69,7 +70,7 @@
<string name="detail_delete_dialog_permanently_delete">Endgültig löschen</string>
<string name="detail_delete_dialog_cancel">Abbrechen</string>
<string name="detail_test_title">Test: Du kannst einen Titel festlegen.</string>
<string name="detail_test_message">Dies ist eine Test-Benachrichtigung aus der ntfy Android-App. Sie hat die Priorität %1$d. Wenn Du eine neue Test-Benachrichtigung sendest, sieht diese vielleicht anders aus.</string>
<string name="detail_test_message">Dies ist eine Test-Benachrichtigung aus der ntfy Android-App. Sie hat die Priorität %1$d. Wenn Du eine neue Test-Benachrichtigung sendest, siehst diese vielleicht anders aus.</string>
<string name="detail_test_message_error">Nachricht kann nicht gesendet werden: %1$s</string>
<string name="detail_test_message_error_unauthorized_user">Nachricht kann nicht gesendet werden: Benutzer \"%1$s\" hat keine Berechtigung.</string>
<string name="detail_test_message_error_too_large">Nachricht kann nicht gesendet werden: Anhang zu groß.</string>
@ -89,7 +90,7 @@
<string name="detail_item_saved_successfully">Wurde als \"%1$s\" im Downloads-Ordner gespeichert</string>
<string name="detail_item_cannot_download">Anhang kann nicht geöffnet oder heruntergeladen werden. Link ist abgelaufen und keine lokale Datei gefunden.</string>
<string name="detail_item_cannot_open">Anhang kann nicht geöffnet werden: %1$s</string>
<string name="detail_item_cannot_open_url">URL kann nicht geöffnet werden: %1$s</string>
<string name="detail_item_cannot_open_click_url">URL kann nicht geöffnet werden: %1$s</string>
<string name="detail_item_cannot_save">Anhang kann nicht gespeichert werden: %1$s</string>
<string name="detail_item_cannot_delete">Anhang kann nicht gelöscht werden: %1$s</string>
<string name="detail_item_download_failed">Herunterladen des Anhangs fehlgeschlagen: %1$s</string>
@ -109,12 +110,12 @@
<string name="share_topic_title">Teilen mit</string>
<string name="share_suggested_topics">Vorgeschlagene Themen</string>
<string name="share_successful">Nachricht veröffentlicht</string>
<string name="notification_dialog_title">Benachrichtigungen stummschalten</string>
<string name="notification_dialog_title">Benachrichtigungen pausieren</string>
<string name="notification_dialog_cancel">Abbrechen</string>
<string name="notification_dialog_save">Speichern</string>
<string name="notification_dialog_enabled_toast_message">Benachrichtigungen aktiviert</string>
<string name="notification_dialog_muted_forever_toast_message">Benachrichtigungen stummgeschaltet</string>
<string name="notification_dialog_muted_until_toast_message">Benachrichtigungen stummgeschaltet bis %1$s</string>
<string name="notification_dialog_muted_forever_toast_message">Benachrichtigungen pausiert</string>
<string name="notification_dialog_muted_until_toast_message">Benachrichtigungen pausiert bis %1$s</string>
<string name="notification_dialog_show_all">Alle Benachrichtigungen anzeigen</string>
<string name="notification_dialog_30min">30 Minuten</string>
<string name="notification_dialog_1h">1 Stunde</string>
@ -135,9 +136,9 @@
\nDatei: %2$s, Herunterladen fehlgeschlagen</string>
<string name="settings_title">Einstellungen</string>
<string name="settings_notifications_header">Benachrichtigungen</string>
<string name="settings_notifications_muted_until_title">Benachrichtigungen stummschalten</string>
<string name="settings_notifications_muted_until_forever">Benachrichtigungen stummgeschaltet bis sie erneut aktiviert werden</string>
<string name="settings_notifications_muted_until_x">Benachrichtigungen stummgeschaltet bis %1$s</string>
<string name="settings_notifications_muted_until_title">Benachrichtigungen pausieren</string>
<string name="settings_notifications_muted_until_forever">Benachrichtigungen pausiert bis sie erneut aktiviert werden</string>
<string name="settings_notifications_muted_until_x">Benachrichtigungen pausiert bis %1$s</string>
<string name="settings_notifications_min_priority_title">Minimale Priorität</string>
<string name="settings_notifications_min_priority_summary_any">Zeigt alle Benachrichtigungen</string>
<string name="settings_notifications_min_priority_summary_x_or_higher">Zeige Benachrichtigungen mit Priorität %1$d (%2$s) oder höher</string>
@ -211,9 +212,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 bewährt, benötigt aber evtl. mehr Akku.</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_broadcast_title">Nachrichten broadcasten</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_summary_ws">WebSockets für die Server-Verbindung nutzen. Diese Methode wird im Juni 2022 der Standard.</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>
@ -232,11 +233,12 @@
<string name="user_dialog_button_cancel">Abbrechen</string>
<string name="user_dialog_button_delete">Benutzer löschen</string>
<string name="user_dialog_button_save">Speichern</string>
<string name="main_menu_notifications_disabled_until">Benachrichtigungen stummgeschaltetbis %1$s</string>
<string name="main_menu_notifications_disabled_until">Benachrichtigungen pausiert bis %1$s</string>
<string name="main_menu_settings_title">Einstellungen</string>
<string name="main_banner_battery_button_remind_later">Später fragen</string>
<string name="main_action_mode_delete_dialog_message">Vom gewählten Thema abmelden und alle Benachrichtigungen endgültig löschen\?</string>
<string name="main_how_to_intro">Klicke den + Button zum Erstellen oder Abonnieren eines Themas. Dann erhältst Du Benachrichtigungen auf dem Gerät, wenn Nachrichten per PUT oder POST veröffentlicht werden.</string>
<string name="main_banner_json_stream_text">Stelle in Einstellungen das Verbindungsprotokoll auf WebSockets um, damit die App sich auch nach Juni 2022 mit Deinem selbst betriebenen Server verbinden kann.</string>
<string name="add_dialog_login_error_not_authorized">Anmeldung fehlgeschlagen. Keine Berechtigung für Benutzer %1$s.</string>
<string name="add_dialog_login_username_hint">Benutzername</string>
<string name="add_dialog_foreground_description">Sofortnachrichten sind für andere Server als %1$s immer aktiviert.</string>
@ -257,7 +259,7 @@
<string name="detail_item_download_info_not_downloaded_expired">nicht heruntergeladen, Link abgelaufen</string>
<string name="detail_item_download_info_deleted_expired">gelöscht, Link abgelaufen</string>
<string name="detail_menu_notifications_enabled">Benachrichtigungen aktiviert</string>
<string name="detail_menu_notifications_disabled_forever">Benachrichtigungen stummgeschaltet</string>
<string name="detail_menu_notifications_disabled_forever">Benachrichtigungen pausiert</string>
<string name="detail_menu_enable_instant">Sofortnachrichten aktivieren</string>
<string name="detail_menu_disable_instant">Sofortnachrichten deaktivieren</string>
<string name="detail_instant_delivery_enabled">Sofortnachrichten aktiviert</string>
@ -267,7 +269,7 @@
<string name="detail_item_download_info_download_failed_expired">Herunterladen fehlgeschlagen, Link ist abgelaufen</string>
<string name="detail_item_download_info_download_failed">Herunterladen fehlgeschlagen</string>
<string name="detail_item_download_info_download_failed_expires_x">Herunterladen fehlgeschlagen, Link läuft ab am/um %1$s</string>
<string name="detail_menu_notifications_disabled_until">Benachrichtigungen stummgeschaltet bis %1$s</string>
<string name="detail_menu_notifications_disabled_until">Benachrichtigungen pausiert bis %1$s</string>
<string name="detail_menu_settings">Abo-Einstellungen</string>
<string name="detail_menu_unsubscribe">Abmelden</string>
<string name="detail_action_mode_delete_dialog_message">Die gewählte(n) Benachrichtigung(en) endgültig löschen\?</string>
@ -299,50 +301,4 @@
\n
\nKennwörter werden immer ersetzt, aber nicht hier aufgelistet.</string>
<string name="detail_deep_link_subscribed_toast_message">Thema %1$s abonniert</string>
<string name="settings_notifications_channel_prefs_title">Kanal-Einstellungen</string>
<string name="settings_notifications_channel_prefs_summary">Übersteuerung von DND (nicht stören), Sounds etc.</string>
<string name="notification_popup_user_action_failed">%1$s fehlgeschlagen: %2$s</string>
<string name="channel_subscriber_notification_instant_text_five">Fünf Sofortnachrichten-Themen abonniert</string>
<string name="channel_subscriber_notification_noinstant_text_five">Fünf Themen abonniert</string>
<string name="channel_subscriber_notification_noinstant_text_six">Sechs Themen abonniert</string>
<string name="detail_settings_notifications_instant_summary_off">Benachrichtigungen werden über Firebase zugestellt. Die Zustellung kann verzögert werden, aber der Akkuverbrauch ist niedriger.</string>
<string name="detail_settings_appearance_header">Darstellung</string>
<string name="detail_settings_appearance_icon_set_title">Abo-Icon</string>
<string name="detail_settings_appearance_icon_set_summary">Ein Icon zur Darstellung in Benachrichtigungen auswählen</string>
<string name="detail_settings_appearance_icon_remove_title">Abo-Icon (entfernen durch Antippen)</string>
<string name="detail_settings_appearance_icon_error_saving">Kann Icon nicht speichern: %1$s</string>
<string name="detail_settings_global_setting_title">Globale Einstellung verwenden</string>
<string name="detail_settings_global_setting_suffix">globale Einstellung</string>
<string name="channel_subscriber_notification_instant_text_six">Sechs Sofortnachrichten-Themen abonniert</string>
<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>
<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>
<string name="detail_settings_appearance_display_name_default_summary">%1$s (Standard)</string>
<string name="detail_settings_appearance_display_name_title">Anzeigename</string>
<string name="detail_settings_appearance_display_name_message">Gib einen eigenen Anzeigenamen für dieses Abo an. Leer lassen für den Standardwert (%1$s).</string>
<string name="detail_settings_about_topic_url_title">Themen-URL</string>
<string name="detail_settings_about_header">Über</string>
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">In Zwischenablage kopiert</string>
<string name="main_menu_donate_title">Spenden 💸</string>
<string name="detail_item_cannot_open_apk">Apps können nicht mehr installiert werden. Bitte stattdessen über einen Browser herunterladen. Details siehe Issue #531.</string>
<string name="detail_settings_notifications_dedicated_channels_summary_on">Verwende eigene Einstellungen für dieses Thema</string>
<string name="detail_settings_notifications_open_channels_title">Beanchrichtigungseinstellungen konfigurieren</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_enabled">Durchgehend alarmieren</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_disabled">Nur einmal alarmieren</string>
<string name="settings_notifications_insistent_max_priority_title">Bei höchster Priorität dauerhaft alarmieren</string>
<string name="channel_notifications_group_default_name">Standard</string>
<string name="settings_notifications_insistent_max_priority_summary_disabled">Benachrichtigungen mit höchster Priorität alarmieren nur einmal</string>
<string name="settings_notifications_insistent_max_priority_summary_enabled">Benachrichtigungen mit höchster Priorität alarmieren dauerhaft bis sie bestätigt werden</string>
<string name="detail_settings_notifications_dedicated_channels_title">Eigene Benachrichtigungseinstellungen</string>
<string name="detail_settings_notifications_dedicated_channels_summary_off">Verwende Standardeinstellungen (Töne, Übergehen von \"Nicht Stören\" etc.)</string>
<string name="detail_settings_notifications_open_channels_summary">„Bitte nicht stören“ unterbrechen, Töne, etc.</string>
<string name="settings_advanced_unifiedpush_summary_disabled">ntfy arbeitet nicht als UnifiedPush-Distributor</string>
<string name="settings_advanced_unifiedpush_title">UnifiedPush aktivieren</string>
<string name="settings_advanced_unifiedpush_summary_enabled">ntfy arbeitet als UnifiedPush-Distributor</string>
<string name="eos_settings_enable_title">Den Verteiler aktivieren</string>
<string name="eos_settings_enable_description">Es ermöglicht Drittanbieteranwendungen, UnifiedPush-Benachrichtigungen zu empfangen</string>
</resources>

View file

@ -1,84 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="main_menu_settings_title">Ρυθμίσεις</string>
<string name="channel_notifications_max_name">Μέγιστη προτεραιότητα</string>
<string name="channel_subscriber_notification_title">Ακρόαση για εισερχόμενες ειδοποιήσεις</string>
<string name="main_menu_report_bug_title">Αναφέρετε ένα σφάλμα</string>
<string name="main_menu_rate_title">Βαθμολογήστε την εφαρμογή ⭐</string>
<string name="main_action_mode_delete_dialog_message">Κατάργηση συνδρομής στο επιλεγμένο θέμα και μόνιμη διαγραφή όλων των ειδοποιήσεων;</string>
<string name="main_action_mode_delete_dialog_permanently_delete">Μόνιμη διαγραφή</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_status_reconnecting">επανασύνδεση…</string>
<string name="main_item_status_unified_push">%1$s (UnifiedPush)</string>
<string name="main_item_date_yesterday">εχθές</string>
<string name="main_add_button_description">Προσθήκη συνδρομής</string>
<string name="channel_notifications_min_name">Ελάχιστη προτεραιότητα</string>
<string name="channel_notifications_low_name">Χαμηλή προτεραιότητα</string>
<string name="channel_subscriber_notification_instant_text">Έχει γίνει εγγραφή σε θέματα άμεσης παράδοσης</string>
<string name="channel_subscriber_notification_instant_text_two">Έχει γίνει εγγραφή σε δύο θέματα άμεσης παράδοσης</string>
<string name="channel_subscriber_notification_instant_text_more">Έχει γίνει εγγραφή σε %1$d θέματα άμεσης παράδοσης</string>
<string name="channel_subscriber_notification_noinstant_text_two">Έχει γίνει εγγραφή σε δύο θέματα</string>
<string name="channel_notifications_high_name">Υψηλή προτεραιότητα</string>
<string name="channel_subscriber_notification_instant_text_four">Έχει γίνει εγγραφή σε τέσσερα θέματα άμεσης παράδοσης</string>
<string name="channel_notifications_default_name">Προκαθορισμένη προτεραιότητα</string>
<string name="channel_subscriber_notification_instant_text_five">Έχει γίνει εγγραφή σε πέντε θέματα άμεσης παράδοσης</string>
<string name="channel_subscriber_service_name">Συνδρομητική υπηρεσία</string>
<string name="channel_subscriber_notification_noinstant_text_three">Έχει γίνει εγγραφή σε τρία θέματα</string>
<string name="channel_subscriber_notification_instant_text_one">Έχει γίνει εγγραφή σε ένα θέμα άμεσης παράδοσης</string>
<string name="channel_subscriber_notification_instant_text_three">Έχει γίνει εγγραφή σε τρία θέματα άμεσης παράδοσης</string>
<string name="channel_subscriber_notification_noinstant_text">Έχει γίνει εγγραφεί σε θέματα</string>
<string name="channel_subscriber_notification_instant_text_six">Έχει γίνει εγγραφή σε έξι θέματα άμεσης παράδοσης</string>
<string name="channel_subscriber_notification_noinstant_text_one">Έχει γίνει εγγραφή σε ένα θέμα</string>
<string name="channel_subscriber_notification_noinstant_text_four">Έχει γίνει εγγραφή σε τέσσερα θέματα</string>
<string name="channel_subscriber_notification_noinstant_text_five">Έχει γίνει εγγραφή σε πέντε θέματα</string>
<string name="channel_subscriber_notification_noinstant_text_six">Έχει γίνει εγγραφή σε έξι θέματα</string>
<string name="channel_subscriber_notification_noinstant_text_more">Έχει γίνει εγγραφή σε %1$d θέματα</string>
<string name="refresh_message_no_results">Όλα είναι ενημερωμένα</string>
<string name="refresh_message_result">Λήφθηκαν %1$d ειδοποίηση/ειδοποιήσεις</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_notifications_disabled_until">Ειδοποιήσεις σε σιωπή μέχρι %1$s</string>
<string name="main_menu_docs_title">Διαβάστε τα έγγραφα</string>
<string name="main_action_mode_menu_unsubscribe">Κατάργηση συνδρομής</string>
<string name="main_action_mode_delete_dialog_cancel">Ακύρωση</string>
<string name="main_no_subscriptions_text">Φαίνεται ότι δεν έχετε ακόμη συνδρομές.</string>
<string name="main_unified_push_toast">Αυτή η συνδρομή διαχειρίζεται από %1$s μέσω του UnifiedPush</string>
<string name="main_how_to_intro">Κάντε κλικ στο + για να δημιουργήσετε ή να εγγραφείτε σε ένα θέμα. Στη συνέχεια, λαμβάνετε ειδοποιήσεις στη συσκευή σας κατά την αποστολή μηνυμάτων μέσω PUT ή POST.</string>
<string name="main_banner_battery_text">Η βελτιστοποίηση μπαταρίας θα πρέπει να είναι απενεργοποιημένη για την εφαρμογή ώστε αποφευχθούν προβλήματα κατά την παράδοσης ειδοποιήσεων.</string>
<string name="main_how_to_link">Λεπτομερείς οδηγίες που διατίθενται στο ntfy.sh, και στα έγγραφα.</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="channel_notifications_group_default_name">Προκαθορισμένο</string>
<string name="add_dialog_description_below">Τα θέματα μπορεί να μην προστατεύονται από κωδικό, οπότε επιλέξτε ένα όνομα που να είναι δύσκολο να μαντευτεί. Όταν εγγραφείτε, θα μπορείτε να κάνετε PUT/POST ειδοποιήσεις.</string>
<string name="add_dialog_topic_name_hint">Όνομα θέματος</string>
<string name="add_dialog_use_another_server">Χρήση άλλου server/εξυπηρετητή</string>
<string name="add_dialog_title">Εγγραφή σε ειδοποίηση</string>
<string name="main_menu_donate_title">Κάντε δωρεά</string>
<string name="main_banner_websocket_text">Η μετάβαση σε WebSockets είναι ο συνιστώμενος τρόπος σύνδεσης με τον διακομιστή σας και μπορεί να βελτιώσει τη διάρκεια ζωής της μπαταρίας, αλλά μπορεί να απαιτεί <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">πρόσθετες ρυθμίσεις στο διακομιστή μεσολάβησης</a>. Αυτό μπορεί να ενεργοποιηθεί στις Ρυθμίσεις.</string>
<string name="add_dialog_login_password_hint">Κωδικός πρόσβασης</string>
<string name="add_dialog_login_error_not_authorized">Η σύνδεση απέτυχε. Ο χρήστης %1$s δεν είναι εξουσιοδοτημένος.</string>
<string name="add_dialog_foreground_description">Η άμεση παράδοση είναι πάντα ενεργή για χρήστες εκτός από τον/την %1$s.</string>
<string name="add_dialog_login_new_user">Νέος χρήστης</string>
<string name="add_dialog_login_title">Απαιτείται σύνδεση</string>
<string name="main_banner_websocket_button_remind_later">Ρωτήστε αργότερα</string>
<string name="add_dialog_instant_delivery_description">Εξασφαλίζει την άμεση παράδοση των μηνυμάτων, ακόμη και αν η συσκευή είναι ανενεργή.</string>
<string name="main_banner_websocket_button_enable_now">Ενεργοποίηση τώρα</string>
<string name="add_dialog_use_another_server_description">Εισάγετε τις παρακάτω διευθύνσεις URL υπηρεσιών για να εγγραφείτε σε θέματα από άλλους διακομιστές.</string>
<string name="add_dialog_button_cancel">Ακύρωση</string>
<string name="add_dialog_error_connection_failed">Η σύνδεση απέτυχε: %1$s</string>
<string name="add_dialog_button_subscribe">Εγγραφή</string>
<string name="add_dialog_button_login">Σύνδεση</string>
<string name="add_dialog_login_username_hint">Όνομα χρήστη</string>
<string name="add_dialog_base_urls_dropdown_choose">Επιλέξτε URL υπηρεσίας</string>
<string name="add_dialog_instant_delivery">Άμεση παράδοση σε κατάσταση doze</string>
<string name="add_dialog_login_description">Αυτό το θέμα απαιτεί να συνδεθείτε. Παρακαλώ πληκτρολογήστε ένα όνομα χρήστη και έναν κωδικό πρόσβασης.</string>
<string name="main_banner_websocket_button_dismiss">Απορρίψτε το</string>
<string name="add_dialog_button_back">Πίσω</string>
</resources>

View file

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View file

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="channel_notifications_min_name">Prioridad mínima</string>
<string name="channel_notifications_min_name">Notificaciones (prioridad mínima)</string>
<string name="detail_item_menu_copy_url">Copiar URL</string>
<string name="notification_popup_action_open">Abrir</string>
<string name="channel_notifications_low_name">Prioridad baja</string>
<string name="channel_notifications_default_name">Prioridad predeterminada</string>
<string name="channel_notifications_max_name">Prioridad máxima</string>
<string name="channel_notifications_low_name">Notificaciones (prioridad baja)</string>
<string name="channel_notifications_default_name">Notificaciones (prioridad por defecto)</string>
<string name="channel_notifications_max_name">Notificaciones (prioridad máxima)</string>
<string name="channel_subscriber_service_name">Servicio de Suscripciones</string>
<string name="channel_subscriber_notification_title">Escuchando por notificaciones entrantes</string>
<string name="channel_subscriber_notification_instant_text_one">Suscrito a un tópico de entrega instantánea</string>
@ -36,7 +36,8 @@
<string name="main_banner_battery_text">La optimización de batería debe deshabilitarse para esta app para evitar problemas con la entrega de notificaciones.</string>
<string name="main_banner_battery_button_remind_later">Preguntar más tarde</string>
<string name="main_banner_battery_button_fix_now">Corregir ahora</string>
<string name="main_banner_websocket_button_dismiss">Descartar</string>
<string name="main_banner_json_stream_button_dismiss">Descartar</string>
<string name="main_banner_json_stream_button_learn_more">Más información</string>
<string name="add_dialog_title">Suscribirse al tópico</string>
<string name="add_dialog_description_below">Los tópicos podrían no estar protegidos por contraseña, así que elija un nombre que sea difícil de adivinar. Una vez suscrito, puede enviar notificaciones con PUT/POST.</string>
<string name="add_dialog_topic_name_hint">Nombre del tópico, p. ej. phils_alerts</string>
@ -70,7 +71,7 @@
<string name="detail_item_menu_copy_contents_copied">Notificación copiada al portapapeles</string>
<string name="detail_item_saved_successfully">Guardado como %1$s en la carpeta de Descargas</string>
<string name="detail_item_cannot_open">No se puede abrir el archivo adjunto: %1$s</string>
<string name="detail_item_cannot_open_url">No se pudo abrir la URL: %1$s</string>
<string name="detail_item_cannot_open_click_url">No se pudo abrir la URL: %1$s</string>
<string name="detail_item_cannot_save">No se puede guardar el archivo adjunto: %1$s</string>
<string name="detail_item_cannot_delete">No se puede eliminar el archivo adjunto: %1$s</string>
<string name="detail_item_download_failed">No se pudo descargar el archivo adjunto: %1$s</string>
@ -88,7 +89,7 @@
<string name="detail_item_menu_cancel">Cancelar descarga</string>
<string name="detail_item_download_info_download_failed">descarga fallida</string>
<string name="detail_menu_notifications_enabled">Notificaciones habilitadas</string>
<string name="detail_menu_notifications_disabled_until">Notificaciones silenciadas hasta %1$s</string>
<string name="detail_menu_notifications_disabled_until">Notificaciones deshabilitadas hasta %1$s</string>
<string name="detail_menu_enable_instant">Habilitar la entrega instantánea</string>
<string name="detail_menu_disable_instant">Deshabilitar la entrega instantánea</string>
<string name="detail_menu_copy_url">Copiar la dirección del tópico</string>
@ -106,10 +107,10 @@
<string name="share_content_file_text">Se ha compartido un archivo contigo</string>
<string name="share_content_file_error">No se pudo leer la información del archivo: %1$s</string>
<string name="share_successful">Mensaje publicado</string>
<string name="notification_dialog_title">Silenciar notificaciones</string>
<string name="notification_dialog_title">Pausar notificaciones</string>
<string name="notification_dialog_cancel">Cancelar</string>
<string name="notification_dialog_save">Guardar</string>
<string name="notification_dialog_muted_until_toast_message">Notificaciones silenciadas hasta %1$s</string>
<string name="notification_dialog_muted_until_toast_message">Notificaciones pausadas hasta %1$s</string>
<string name="notification_dialog_show_all">Mostrar todas las notificaciones</string>
<string name="notification_dialog_30min">30 minutos</string>
<string name="notification_dialog_1h">1 hora</string>
@ -128,10 +129,10 @@
\nArchivo: %2$s, descarga fallida</string>
<string name="settings_title">Ajustes</string>
<string name="settings_notifications_header">Notificaciones</string>
<string name="settings_notifications_muted_until_title">Silenciar notificaciones</string>
<string name="settings_notifications_muted_until_title">Pausar notificaciones</string>
<string name="settings_notifications_muted_until_show_all">Se mostrarán todas las notificaciones</string>
<string name="settings_notifications_muted_until_forever">Notificaciones silenciadas hasta que se re-habiliten</string>
<string name="settings_notifications_muted_until_x">Notificaciones silenciadas hasta %1$s</string>
<string name="settings_notifications_muted_until_forever">Notificaciones deshabilitadas hasta que se re-habiliten</string>
<string name="settings_notifications_muted_until_x">Notificaciones deshabilitadas hasta %1$s</string>
<string name="settings_notifications_min_priority_title">Prioridad mínima</string>
<string name="settings_notifications_min_priority_summary_max">Mostrar notificaciones si la prioridad es 5 (máximo)</string>
<string name="settings_notifications_min_priority_min">Cualquier prioridad</string>
@ -205,8 +206,8 @@
<string name="settings_advanced_clear_logs_summary">Borrar los registros anteriores y empezar de nuevo</string>
<string name="settings_advanced_clear_logs_deleted_toast">Registros eliminados</string>
<string name="settings_advanced_connection_protocol_title">Protocolo de conexión</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Usar un JSON stream sobre HTTP para conectarse al servidor. Este método está probado en batalla pero puede consumir más batería.</string>
<string name="settings_advanced_connection_protocol_summary_ws">Usar WebSockets para conectarse al servidor. Este es el método recomendado, pero puede requerir configuración adicional en su proxy.</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Usar un JSON stream sobre HTTP para conectarse al servidor. Este método es obsoleto y será removido en junio de 2022.</string>
<string name="settings_advanced_connection_protocol_summary_ws">Usar WebSockets para conectarse al servidor. Esta opción será la predeterminada en junio de 2022.</string>
<string name="settings_advanced_connection_protocol_entry_jsonhttp">JSON stream sobre HTTP</string>
<string name="settings_advanced_connection_protocol_entry_ws">WebSockets</string>
<string name="settings_about_version_title">Versión</string>
@ -221,7 +222,7 @@
<string name="user_dialog_button_add">Añadir usuario</string>
<string name="user_dialog_button_cancel">Cancelar</string>
<string name="user_dialog_button_save">Guardar</string>
<string name="channel_notifications_high_name">Prioridad alta</string>
<string name="channel_notifications_high_name">Notificaciones (prioridad alta)</string>
<string name="channel_subscriber_notification_instant_text">Suscrito a tópicos de entrega instantánea</string>
<string name="main_item_status_unified_push">%1$s (UnifiedPush)</string>
<string name="add_dialog_use_another_server_description">Introduzca las URL de servicio para suscribirse a los tópicos de otros servidores.</string>
@ -231,7 +232,7 @@
<string name="channel_subscriber_notification_instant_text_three">Suscrito a tres tópicos de entrega instantánea</string>
<string name="channel_subscriber_notification_noinstant_text_one">Suscrito a un tópico</string>
<string name="channel_subscriber_notification_noinstant_text_three">Suscrito a tres tópicos</string>
<string name="main_menu_notifications_disabled_until">Notificaciones silenciadas hasta %1$s</string>
<string name="main_menu_notifications_disabled_until">Notificaciones deshabilitadas hasta %1$s</string>
<string name="add_dialog_error_connection_failed">Error de conexión: %1$s</string>
<string name="detail_item_menu_save_file">Guardar archivo</string>
<string name="detail_menu_settings">Ajustes de la suscripción</string>
@ -250,7 +251,7 @@
<string name="notification_dialog_enabled_toast_message">Notificaciones re-habilitadas</string>
<string name="settings_notifications_auto_delete_summary_three_months">Eliminar automáticamente las notificaciones después de 3 meses</string>
<string name="detail_item_cannot_open_not_found">No se puede abrir el archivo adjunto: El archivo puede haber sido borrado, o ninguna aplicación instalada puede abrir el archivo.</string>
<string name="detail_menu_notifications_disabled_forever">Notificaciones silenciadas</string>
<string name="detail_menu_notifications_disabled_forever">Notificaciones deshabilitadas</string>
<string name="notification_dialog_2h">2 horas</string>
<string name="settings_general_dark_mode_summary_dark">Modo oscuro activado. ¿Eres un vampiro\?</string>
<string name="settings_general_default_base_url_message">Introduzca la URL base de su servidor para utilizarlo como predeterminado cuando se suscriba a nuevos tópicos y/o se comparta a ellos.</string>
@ -261,7 +262,7 @@
<string name="detail_menu_unsubscribe">Cancelar la suscripción</string>
<string name="detail_item_menu_copy_contents">Copiar notificación</string>
<string name="detail_settings_title">Ajustes de la suscripción</string>
<string name="notification_dialog_muted_forever_toast_message">Notificaciones silenciadas</string>
<string name="notification_dialog_muted_forever_toast_message">Notificaciones pausadas</string>
<string name="notification_dialog_tomorrow">Hasta mañana</string>
<string name="settings_notifications_min_priority_summary_x_or_higher">Mostrar notificaciones si la prioridad es %1$d (%2$s) o superior</string>
<string name="settings_notifications_auto_download_title">Descargar archivos adjuntos</string>
@ -269,14 +270,14 @@
<string name="settings_notifications_auto_delete_one_day">Después de un día</string>
<string name="settings_general_users_prefs_user_add_title">Añadir nuevo usuario</string>
<string name="user_dialog_button_delete">Eliminar usuario</string>
<string name="main_menu_notifications_disabled_forever">Notificaciones silenciadas</string>
<string name="main_menu_notifications_disabled_forever">Notificaciones deshabilitadas</string>
<string name="settings_notifications_min_priority_max">Sólo prioridad máxima</string>
<string name="settings_notifications_auto_download_50m">Si es más pequeño que 50 MB</string>
<string name="settings_notifications_auto_delete_one_week">Después de una semana</string>
<string name="settings_general_dark_mode_summary_light">Modo claro activado</string>
<string name="settings_backup_restore_restore_summary">Importar configuración, notificaciones y usuarios</string>
<string name="user_dialog_description_edit">Puede editar el nombre de usuario / contraseña para el usuario seleccionado o eliminarlo.</string>
<string name="main_banner_websocket_button_remind_later">Preguntar más tarde</string>
<string name="main_banner_json_stream_button_remind_later">Preguntar más tarde</string>
<string name="add_dialog_foreground_description">La entrega instantánea siempre está habilitada para los hosts que no sean %1$s.</string>
<string name="add_dialog_login_title">Se requiere inicio de sesión</string>
<string name="main_action_mode_delete_dialog_permanently_delete">Eliminar permanentemente</string>
@ -288,6 +289,7 @@
<string name="main_menu_rate_title">Califica la aplicación ⭐</string>
<string name="main_unified_push_toast">Esta suscripción es gestionada por %1$s a través de UnifiedPush</string>
<string name="main_banner_battery_button_dismiss">Descartar</string>
<string name="main_banner_json_stream_text">Cambie a WebSockets en Ajustes / \"Protocolo de conexión\" ahora para asegurarse de que puede comunicarse con su servidor autoalojado ntfy después de junio de 2022.</string>
<string name="add_dialog_use_another_server">Usar otro servidor</string>
<string name="detail_how_to_link">Instrucciones detalladas están disponibles en ntfy.sh y en la documentación.</string>
<string name="main_menu_settings_title">Ajustes</string>
@ -298,51 +300,4 @@
<string name="settings_notifications_priority_default">default</string>
<string name="settings_notifications_priority_min">mínima</string>
<string name="settings_notifications_priority_low">baja</string>
<string name="detail_deep_link_subscribed_toast_message">Suscrito al tópico %1$s</string>
<string name="settings_notifications_channel_prefs_title">Ajustes del canal</string>
<string name="settings_notifications_channel_prefs_summary">Ignorar No Molestar (DND), sonidos, etc.</string>
<string name="notification_popup_user_action_failed">%1$s ha fallado: %2$s</string>
<string name="channel_subscriber_notification_instant_text_five">Suscrito a cinco tópicos de entrega instantánea</string>
<string name="channel_subscriber_notification_instant_text_six">Suscrito a seis tópicos de entrega instantánea</string>
<string name="channel_subscriber_notification_noinstant_text_five">Suscrito a cinco tópicos</string>
<string name="channel_subscriber_notification_noinstant_text_six">Suscrito a seis tópicos</string>
<string name="detail_settings_notifications_instant_summary_on">Las notificaciones se entregan al instante. Requiere un servicio en primer plano y consume más batería.</string>
<string name="detail_settings_appearance_header">Apariencia</string>
<string name="detail_settings_appearance_icon_set_title">Icono de suscripción</string>
<string name="detail_settings_appearance_icon_remove_title">Icono de suscripción (toque para eliminar)</string>
<string name="detail_settings_appearance_icon_remove_summary">El icono mostrado en notificaciones para este tópico</string>
<string name="detail_settings_appearance_icon_error_saving">No se puede guardar el icono: %1$s</string>
<string name="detail_settings_global_setting_title">Usar la configuración global</string>
<string name="detail_settings_global_setting_suffix">usando la configuración global</string>
<string name="detail_settings_notifications_instant_summary_off">Las notificaciones se entregan usando Firebase. La entrega puede retrasarse, pero consume menos batería.</string>
<string name="detail_settings_notifications_instant_title">Entrega instantánea</string>
<string name="detail_settings_appearance_icon_set_summary">Establecer un icono para que aparezca en las notificaciones</string>
<string name="detail_settings_appearance_display_name_title">Nombre a mostrar</string>
<string name="detail_settings_appearance_display_name_default_summary">%1$s (predeterminado)</string>
<string name="detail_settings_appearance_display_name_message">Establezca un nombre a mostrar para esta suscripción. Deje en blanco para usar el valor predeterminado (%1$s).</string>
<string name="detail_settings_about_header">Acerca de</string>
<string name="detail_settings_about_topic_url_title">URL del tópico</string>
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">Copiado a portapapeles</string>
<string name="add_dialog_base_urls_dropdown_choose">Elija la URL del servicio</string>
<string name="add_dialog_base_urls_dropdown_clear">Borrar la URL del servicio</string>
<string name="main_banner_websocket_text">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 <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">configuración adicional en su proxy</a>. Esto se puede cambiar en la Configuración.</string>
<string name="main_banner_websocket_button_enable_now">Habilitar ahora</string>
<string name="main_menu_donate_title">Donar 💸</string>
<string name="detail_item_cannot_open_apk">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.</string>
<string name="channel_notifications_group_default_name">Predeterminado</string>
<string name="settings_notifications_insistent_max_priority_title">Mantener alertas para la máxima prioridad</string>
<string name="settings_notifications_insistent_max_priority_summary_enabled">Las notificaciones de prioridad máxima alertan continuamente hasta que se descartan</string>
<string name="settings_notifications_insistent_max_priority_summary_disabled">Las notificaciones de prioridad máxima solo alertan una vez</string>
<string name="detail_settings_notifications_open_channels_summary">Ignorar No Molestar (DND), sonidos, etc.</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_enabled">Seguir alertando</string>
<string name="detail_settings_notifications_dedicated_channels_title">Configuración de notificaciones personalizadas</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_disabled">Alertar solo una vez</string>
<string name="detail_settings_notifications_dedicated_channels_summary_on">Utilizando configuración personalizada para esta suscripción</string>
<string name="detail_settings_notifications_dedicated_channels_summary_off">Utilizando configuración predeterminada (sonidos, no molestar, etc.)</string>
<string name="detail_settings_notifications_open_channels_title">Configuración de la notificación</string>
<string name="settings_advanced_unifiedpush_title">Activar UnifiedPush</string>
<string name="settings_advanced_unifiedpush_summary_enabled">ntfy actuará como distribuidor UnifiedPush</string>
<string name="settings_advanced_unifiedpush_summary_disabled">ntfy no actuará como distribuidor UnifiedPush</string>
<string name="eos_settings_enable_title">Habilitar el distribuidor</string>
<string name="eos_settings_enable_description">Permite a las aplicaciones de terceros recibir notificaciones de UnifiedPush</string>
</resources>

View file

@ -1,42 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="channel_notifications_min_name">اولویت اصلی</string>
<string name="channel_notifications_default_name">اولویت پیش تعریف</string>
<string name="channel_notifications_low_name">اولویت پایین</string>
<string name="channel_notifications_group_default_name">پیش تعریف</string>
<string name="channel_subscriber_notification_instant_text">عضویت یافته در تحویل فوری اطلاعیه ها</string>
<string name="channel_subscriber_notification_instant_text_one">عضویت یافته در تحویل یک موضوع</string>
<string name="channel_subscriber_notification_instant_text_three">عضویت یافته در دریافت سه موضوع</string>
<string name="channel_subscriber_notification_instant_text_five">عضویت یافته در دریافت پنج موضوع</string>
<string name="channel_subscriber_notification_instant_text_more">عضویت یافته در دریافت %1$d موضوع</string>
<string name="channel_subscriber_notification_noinstant_text">عضویت یافته در موضوعات</string>
<string name="main_menu_settings_title">تنظیمات</string>
<string name="main_menu_report_bug_title">گزارش یک نقص فنی</string>
<string name="main_menu_docs_title">مطالعه مستندات</string>
<string name="main_menu_rate_title">رتبه دهی به اپ ⭐</string>
<string name="main_menu_donate_title">حمایت مالی 💸</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_status_reconnecting">در حال اتصال دوباره …</string>
<string name="main_item_date_yesterday">دیروز</string>
<string name="main_no_subscriptions_text">به نظر می رسد شما هنوز هیچ عضویتی ندارید.</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_title">گوش به زنگ دریافت اطلاعیه</string>
<string name="channel_subscriber_notification_instant_text_two">عضویت یافته در دریافت دو موضوع</string>
<string name="channel_subscriber_notification_instant_text_four">عضویت یافته در دریافت چهار موضوع</string>
<string name="channel_subscriber_notification_instant_text_six">عضویت یافته در دریافت شش موضوع</string>
<string name="channel_subscriber_notification_noinstant_text_one">عضویت یافته در یک موضوع</string>
<string name="refresh_message_result">%1$d اطلاعیه دریافت شد</string>
<string name="refresh_message_no_results">همه چیز بروزآوری شده است</string>
<string name="refresh_message_error_one">بروزآوری آبونمان %1$s ناموفق بود</string>
<string name="main_menu_notifications_enabled">ارسال اطلاعیه در</string>
<string name="main_menu_notifications_disabled_forever">اطلاعیه ها بی صدا شده اند</string>
<string name="main_menu_notifications_disabled_until">اطلاعیه ها تا %1$s بی صدا شده اند</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_add_button_description">افزون اشتراک</string>
</resources>

View file

@ -1,346 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="user_dialog_button_add">Lisää käyttäjä</string>
<string name="settings_backup_restore_backup_entry_everything_no_users">Kaikki, paitsi käyttäjät</string>
<string name="add_dialog_login_password_hint">Salasana</string>
<string name="add_dialog_login_error_not_authorized">Kirjautuminen epäonnistui %1$s ei oikeuksia.</string>
<string name="settings_general_header">Pääkäyttäjä</string>
<string name="add_dialog_foreground_description">Välitön toimitus on aina päällä muille palvelimille kuin %1$s.</string>
<string name="detail_clear_dialog_message">Poistetaanko kaikki tämän topikin ilmoitukset \?</string>
<string name="channel_subscriber_notification_instant_text">Tilattu välittömään topikkiin</string>
<string name="detail_settings_appearance_display_name_title">Näytön nimi</string>
<string name="detail_item_menu_copy_url_copied">URL kopioitu leikkelepöydälle</string>
<string name="detail_item_snack_deleted">Ilmoitus poistettu</string>
<string name="settings_advanced_export_logs_entry_copy_original">Kopioi leikkelepöydälle</string>
<string name="settings_advanced_broadcast_summary_disabled">Sovellukset eivät voi vastaanottaa ilmoituksia ja lähetyksiä</string>
<string name="detail_menu_clear">Poista kaikki ilmoitukset</string>
<string name="channel_notifications_max_name">Maksimi tärkeys</string>
<string name="settings_advanced_export_logs_scrub_dialog_empty">Aiheita/isäntänimiä ei ole muokattu. Ehkä sinulla ei ole topikkeja\?</string>
<string name="add_dialog_login_new_user">Uusi käyttäjä</string>
<string name="user_dialog_description_add">Kaikki tietyn palvelimen topikit käyttävät tätä käyttäjää.</string>
<string name="share_content_text_hint">Lisää jaettavaksi täällä</string>
<string name="settings_backup_restore_backup_title">Varmuuskopioi tiedostoon</string>
<string name="share_successful">Viesti julkaistu</string>
<string name="settings_advanced_clear_logs_title">Tyhjennä logit</string>
<string name="settings_general_users_title">Hallitse käyttäjiä</string>
<string name="add_dialog_login_title">Kirjautuminen tarvitaan</string>
<string name="settings_notifications_priority_min">min</string>
<string name="settings_notifications_auto_delete_summary_never">Älä koskaan poista automaattisesti ilmoituksia</string>
<string name="notification_popup_file_download_successful">%1$s
\nTiedosto: %2$s, ladattu</string>
<string name="notification_popup_action_browse">Julkaise</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_enabled">Jatka hälyttämistä</string>
<string name="settings_advanced_broadcast_title">Lähetä viestejä</string>
<string name="main_menu_rate_title">Äänestä aplikaatiota</string>
<string name="detail_item_cannot_delete">Ei voida poistaa liitettä %1$s</string>
<string name="settings_backup_restore_backup_summary">Vie asetukset, ilmoitukset ja käyttäjät</string>
<string name="notification_popup_file_downloading">Lataa %1$s, %2$d%%
\n%3$s</string>
<string name="main_item_status_text_not_one">%1$d Huomautusta</string>
<string name="user_dialog_description_edit">Voit muokata valitun käyttäjän käyttäjätunnusta/salasanaa tai poistaa sen.</string>
<string name="notification_dialog_show_all">Näytä kaikki ilmoitukset</string>
<string name="settings_notifications_min_priority_min">Kaikki tärkeydet</string>
<string name="notification_dialog_30min">30 minuuttia</string>
<string name="detail_item_menu_delete">Poista tiedosto</string>
<string name="channel_subscriber_notification_instant_text_two">Tilattu kahteen välittömään topikkiin</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_disabled">Tee hälytys vain kerran</string>
<string name="settings_notifications_auto_download_never">Älä koskaan lataa automaattisesti mitään</string>
<string name="notification_popup_user_action_failed">%1$s epäonnistunut: %2$s</string>
<string name="settings_advanced_export_logs_entry_upload_scrubbed">Tallenna ja kopioi linkki (sensuroitu)</string>
<string name="refresh_message_result">%1$d ilmoitusta vastaanotettu</string>
<string name="notification_dialog_1h">1 tunti</string>
<string name="detail_settings_notifications_instant_title">Välitön lähetys</string>
<string name="notification_dialog_forever">Jatkamiseen asti</string>
<string name="settings_notifications_auto_delete_summary_one_week">Poista ilmoitukset viikon jälkeen</string>
<string name="settings_advanced_export_logs_error_uploading">Ei voida tallentaa logia: %1$s</string>
<string name="detail_item_download_info_not_downloaded_expires_x">Ei ladattu, vanhentunut %1$s</string>
<string name="detail_no_notifications_text">Et ole vielä saanut yhtään ilmoitusta tästä topikista.</string>
<string name="detail_item_cannot_open_url">Ei voida avata URL: %1$s</string>
<string name="settings_notifications_min_priority_title">Pienin prioriteetti</string>
<string name="share_menu_send">Jaa</string>
<string name="channel_subscriber_notification_noinstant_text_two">Tilattu kahteen topikkiin</string>
<string name="detail_settings_title">Tilausasetukset</string>
<string name="detail_item_saved_successfully">Tallennettu nimellä %1$s lataukset kansioon</string>
<string name="settings_notifications_auto_delete_one_month">jälkeen kolmenkymmenen päivän</string>
<string name="channel_notifications_group_default_name">Oletus</string>
<string name="detail_menu_test">Lähetä testi ilmoitus</string>
<string name="settings_notifications_priority_high">korkea</string>
<string name="main_no_subscriptions_text">Näyttää siltä, että sinulla ei ole vielä tilauksia.</string>
<string name="settings_general_users_prefs_user_add_title">Lisää uusi käyttäjä</string>
<string name="detail_menu_disable_instant">Poista välittömät ilmoitukset käytöstä</string>
<string name="detail_action_mode_delete_dialog_cancel">Peruuta</string>
<string name="channel_subscriber_notification_noinstant_text_more">Tilattu %1$d topikkiin</string>
<string name="settings_advanced_export_logs_entry_upload_original">Tallenna ja kopioi linkki</string>
<string name="main_banner_battery_button_fix_now">Korjaa nyt</string>
<string name="detail_item_download_info_not_downloaded">Ei ladattu</string>
<string name="user_dialog_button_save">Tallenna</string>
<string name="detail_delete_dialog_cancel">Peruuta</string>
<string name="settings_about_version_copied_to_clipboard_message">Kopioitu leikkelepöydälle</string>
<string name="notification_popup_action_download">Lataa</string>
<string name="detail_item_cannot_download">Liitettä ei voi avata tai ladata. Linkki vanhentui, eikä paikallista tiedostoa löytynyt.</string>
<string name="main_menu_notifications_enabled">Huomautukset päällä</string>
<string name="settings_general_dark_mode_summary_system">Käytä järjestelmän oletusta</string>
<string name="main_menu_notifications_disabled_forever">Hiljennetyt huomautukset</string>
<string name="detail_item_menu_download">Lataa tiedosto</string>
<string name="channel_subscriber_notification_instant_text_six">Tilattu kuuteen välittömään topikkiin</string>
<string name="main_banner_websocket_button_remind_later">Kysy myöhemmin</string>
<string name="detail_item_menu_copy_contents_copied">Ilmoitus kopioitu leikkelepöydälle</string>
<string name="settings_general_users_prefs_user_used_by_one">Käytetty topikissa %1$s</string>
<string name="detail_settings_appearance_header">Ulkoasu</string>
<string name="settings_notifications_auto_delete_summary_one_month">Poista ilmoitukset kuukauden jälkeen</string>
<string name="channel_subscriber_notification_instant_text_three">Tilattu kolmeen välittömään topikkiin</string>
<string name="channel_subscriber_service_name">Tilaus palvelu</string>
<string name="channel_subscriber_notification_instant_text_five">Tilattu viiteen välittömään topikkiin</string>
<string name="settings_general_users_prefs_user_add">Lisää käyttäjiä</string>
<string name="settings_notifications_auto_delete_three_months">jälkeen kolmen kuukauden</string>
<string name="main_add_button_description">Lisää tilaus</string>
<string name="notification_dialog_muted_forever_toast_message">Ilmoitukset hiljennetty</string>
<string name="settings_notifications_muted_until_show_all">Näytä kaikki ilmoitukset</string>
<string name="notification_popup_file_download_failed">%1$s
\ntiedosto: %2$s, lataus virhe</string>
<string name="main_action_mode_delete_dialog_permanently_delete">Poista pysyvästi</string>
<string name="settings_notifications_auto_delete_three_days">Jälkeen kolmen päivän</string>
<string name="settings_general_dark_mode_summary_light">Vaalea tila päälle</string>
<string name="detail_item_cannot_open">Ei voida avata liitettä %1$s</string>
<string name="settings_notifications_auto_download_5m">Jos tiedoston koko on alle 5 MB</string>
<string name="settings_general_dark_mode_entry_light">Vaalea tila</string>
<string name="detail_item_cannot_open_not_found">Liitettä ei voi avata: Tiedosto on ehkä poistettu tai mikään asennettu sovellus ei voi avata tiedostoa.</string>
<string name="settings_general_dark_mode_title">Tumma tila</string>
<string name="detail_item_download_failed">Ei voida ladata tiedostoa: %1$s</string>
<string name="settings_about_version_title">Versio</string>
<string name="channel_notifications_default_name">Oletus tärkeys</string>
<string name="detail_item_download_info_download_failed">Lataus epäonnistunut</string>
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">Kopoitu leikkelepöydälle</string>
<string name="settings_notifications_min_priority_high">Korkea prioriteetti ja sen ylittävät</string>
<string name="settings_notifications_insistent_max_priority_summary_disabled">Tärkeimmät ilmoitukset hälyttävät vain kerran</string>
<string name="add_dialog_description_below">Topikit eivät ole salasanasuojattuja, joten valitse nimi, jota on vaikea arvata. Kun olet tilannut, voit käyttää PUT/POST ilmoituksia.</string>
<string name="settings_backup_restore_header">Varmuuskopioi &amp; palauta</string>
<string name="main_item_status_reconnecting">Uudelleen yhdistää …</string>
<string name="detail_delete_dialog_message">Lopetetaanko tämän aiheen tilaus ja poistetaanko kaikki saamasi ilmoitukset\?</string>
<string name="settings_title">Asetukset</string>
<string name="settings_general_dark_mode_entry_dark">Tumma tila</string>
<string name="share_content_file_error">Tiedostoa ei voi lukea info: %1$s</string>
<string name="add_dialog_instant_delivery_description">Varmistaa, että viestit toimitetaan välittömästi, vaikka laite olisi passiivinen.</string>
<string name="detail_action_mode_menu_delete">Poista</string>
<string name="main_menu_notifications_disabled_until">Huomautukset hiljennetty %1$s saakka</string>
<string name="detail_item_download_info_deleted_expires_x">Poistettu, linkki vanhentuu %1$s</string>
<string name="main_banner_websocket_button_enable_now">Ota käyttöön</string>
<string name="main_item_date_yesterday">Eilen</string>
<string name="detail_settings_notifications_dedicated_channels_summary_on">Mukautettujen asetusten käyttäminen tälle tilaukselle</string>
<string name="settings_advanced_unifiedpush_summary_disabled">ntfy ei toimi UnifiedPush-jakelijana</string>
<string name="detail_settings_global_setting_suffix">Käytetään globaalia asetusta</string>
<string name="detail_clear_dialog_permanently_delete">Poista pysyvästi</string>
<string name="main_banner_battery_button_remind_later">Kysy myöhemmin</string>
<string name="channel_notifications_min_name">Pieni tärkeys</string>
<string name="notification_popup_action_open">Auki</string>
<string name="detail_item_menu_open">Avaa tiedosto</string>
<string name="settings_notifications_insistent_max_priority_summary_enabled">Tärkeimmät ilmoitukset hälyttävät jatkuvasti, kunnes ne hylätään</string>
<string name="main_how_to_link">Yksityiskohtaiset ohjeet löytyvät osoitteesta ntfy.sh .</string>
<string name="settings_notifications_channel_prefs_summary">Älä häiritse tila (DND) äänet, jne.</string>
<string name="settings_general_users_prefs_user_not_used">Ei käytetty missään topikissa</string>
<string name="detail_how_to_link">Yksityiskohtaiset ohjeet ovat saatavilla osoitteessa ntfy.sh ja dokumenteissa.</string>
<string name="settings_notifications_muted_until_title">Hiljennetyt ilmoitukset</string>
<string name="detail_test_message_error">Ei voida lähettää: %1$s</string>
<string name="channel_subscriber_notification_noinstant_text_four">Tilattu neljään topikkiin</string>
<string name="settings_general_default_base_url_default_summary">%1$s (oletus)</string>
<string name="detail_instant_delivery_enabled">Välitön lähetys päällä</string>
<string name="notification_dialog_2h">2 tuntia</string>
<string name="settings_backup_restore_backup_entry_everything">Kaikki</string>
<string name="settings_general_users_summary">Lisää/poista käyttäjiä suojatuille topikeille</string>
<string name="add_dialog_use_another_server_description">Syötä palvelun URL-osoitte alle tilataksesi topikkeja muilta palvelimilta.</string>
<string name="settings_notifications_auto_delete_one_day">Jälkeen yhden päivän</string>
<string name="settings_general_dark_mode_summary_dark">Tumma tila päällä. Oletko vampyyri \?</string>
<string name="settings_general_users_prefs_user_add_summary">Lisää uusi käyttäjä uudelle palvelimelle</string>
<string name="settings_general_dark_mode_entry_system">Käytä oletusasetusta</string>
<string name="notification_dialog_save">Tallenna</string>
<string name="user_dialog_base_url_hint">Palvelun URL</string>
<string name="detail_item_download_info_download_failed_expires_x">Lataus epäonnistunut, linkki vanhentunut %1$s</string>
<string name="settings_notifications_priority_max">max</string>
<string name="user_dialog_password_hint_add">Salasana</string>
<string name="settings_notifications_min_priority_summary_any">Näytä kaikki ilmoitukset</string>
<string name="main_unified_push_toast">%1$s hallinnoi tätä tilausta UnifiedPushin kautta</string>
<string name="detail_item_menu_copy_contents">Kopioi ilmoitus</string>
<string name="channel_subscriber_notification_instant_text_more">Tilattu %1$d välittömään topikkiin</string>
<string name="detail_menu_enable_instant">Ota välittömät ilmoitukset käyttöön</string>
<string name="settings_advanced_export_logs_summary">Kopioi lokit leikepöydälle tai lataa osoitteeseen nopaste.net (omistaja ntfy). Isäntänimet ja aiheet voidaan sensuroida, ilmoituksia ei koskaan tehdä.</string>
<string name="detail_action_mode_delete_dialog_permanently_delete">Poista pysyvästi</string>
<string name="notification_dialog_enabled_toast_message">Jatka ilmoituksia</string>
<string name="main_menu_report_bug_title">Raportoi bugista</string>
<string name="add_dialog_button_cancel">Peruuta</string>
<string name="settings_notifications_min_priority_summary_max">Näytä ilmoitukset jos tärkeys on 5 (max)</string>
<string name="settings_advanced_broadcast_summary_enabled">Sovellukset voivat vastaanottaa saapuvia ilmoituksia ja lähetyksiä</string>
<string name="notification_dialog_tomorrow">Huomiseen saakka</string>
<string name="detail_settings_notifications_open_channels_title">Määritä ilmoitusasetukset</string>
<string name="add_dialog_topic_name_hint">Topikin nimi, esimerkiksi pentin_hälytykset</string>
<string name="channel_notifications_low_name">Matala tärkeys</string>
<string name="settings_notifications_auto_download_title">Lataa liitteet</string>
<string name="user_dialog_button_delete">Poista käyttäjä</string>
<string name="add_dialog_error_connection_failed">Yhteys epäonnistui: %1$s</string>
<string name="detail_menu_notifications_disabled_forever">Ilmoitukset hiljennetty</string>
<string name="share_content_image_text">Kanssasi jaettiin kuva</string>
<string name="main_banner_websocket_text">WebSocketsiin vaihtaminen on suositeltu tapa muodostaa yhteys palvelimeesi, ja se voi parantaa akun käyttöikää, mutta saattaa edellyttää <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">additional config in your proxy</a>. Tämän voi vaihtaa asetuksista.</string>
<string name="settings_notifications_channel_prefs_title">Kanavan asetukset</string>
<string name="settings_notifications_auto_download_50m">Jos tiedoston koko on alle 50 MB</string>
<string name="detail_clear_dialog_cancel">Peruuta</string>
<string name="main_action_mode_delete_dialog_cancel">Peruuta</string>
<string name="settings_notifications_min_priority_default">Oletus prioriteetin ja sen ylittävät</string>
<string name="detail_test_message_error_unauthorized_anon">Viestiä ei voi lähettää: Nimetöntä lähetystä ei sallita.</string>
<string name="settings_advanced_connection_protocol_entry_ws">WebSocketit</string>
<string name="detail_copied_to_clipboard_message">Kopioitu leikepöydälle</string>
<string name="channel_subscriber_notification_noinstant_text">Tilattu topikkiin</string>
<string name="detail_action_mode_menu_copy">Kopioi</string>
<string name="settings_advanced_connection_protocol_entry_jsonhttp">JSON stream yli HTTP</string>
<string name="user_dialog_title_add">Lisää käyttäjä</string>
<string name="detail_item_download_info_deleted">Poistettu</string>
<string name="add_dialog_button_subscribe">Tilaa</string>
<string name="settings_advanced_clear_logs_deleted_toast">Logit poistettu</string>
<string name="detail_item_download_info_downloading_x_percent">%1$d%% ladattu</string>
<string name="user_dialog_button_cancel">Peruuta</string>
<string name="add_dialog_button_login">Kirjaudu</string>
<string name="settings_backup_restore_restore_summary">Tuo asetukset, ilmoitukset ja käyttäjät</string>
<string name="channel_subscriber_notification_title">Kuuntelee sisääntulevia viestejä</string>
<string name="detail_how_to_intro">Jos haluat lähettää ilmoituksia tähän topikkiin, lähetä PUT tai POST topikin URL-osoitteeseen.</string>
<string name="settings_general_users_prefs_title">Käyttäjät</string>
<string name="detail_item_cannot_open_apk">Sovelluksia ei voi enää asentaa. Lataa sen sijaan selaimen kautta. Katso numero #531 saadaksesi lisätietoja.</string>
<string name="settings_advanced_clear_logs_summary">Poista aiemmin tallennetut lokit ja aloita alusta</string>
<string name="refresh_message_error_one">Ei voitu päivittää: %1$s</string>
<string name="add_dialog_login_username_hint">Käyttäjänimi</string>
<string name="detail_settings_about_header">-</string>
<string name="settings_advanced_export_logs_uploading">Tallenna logi …</string>
<string name="detail_item_menu_copy_url">Kopioi URL</string>
<string name="detail_menu_notifications_disabled_until">Ilmoitukset hiljennetty %1$s asti</string>
<string name="settings_advanced_export_logs_scrub_dialog_text">Nämä aiheet/isäntänimet korvattiin hedelmien nimillä, joten voit jakaa lokin huoletta:
\n
\n%1$s
\n
\nSalasanat on poistettu, ja niitä ei ole listattu tässä.</string>
<string name="settings_advanced_unifiedpush_summary_enabled">ntfy toimii UnifiedPush-jakelijana</string>
<string name="add_dialog_use_another_server">Käytä eri palvelinta</string>
<string name="settings_notifications_priority_default">oletus</string>
<string name="settings_notifications_auto_download_100k">Jos tiedoston koko on alle 100 kB</string>
<string name="add_dialog_base_urls_dropdown_choose">Valitse palvelimen URL</string>
<string name="add_dialog_instant_delivery">Välitön toimitus torkkutilassa</string>
<string name="settings_notifications_auto_delete_title">Poista ilmoitukset</string>
<string name="detail_delete_dialog_permanently_delete">Poista pysyvästi</string>
<string name="share_content_title">Viestin esikatselu</string>
<string name="settings_notifications_auto_download_500k">Jos tiedoston koko on alle 500 kB</string>
<string name="settings_general_default_base_url_title">Oletuspalvelin</string>
<string name="settings_notifications_muted_until_x">Ilmoitukset mykistetty, %1$s saakka</string>
<string name="main_banner_battery_text">Akun optimoinnin tulee olla pois päältä ilmoitusten toimitusongelmien välttämiseksi.</string>
<string name="settings_advanced_unifiedpush_title">Ota käyttöön UnifiedPush</string>
<string name="settings_general_default_base_url_message">Anna palvelimesi juurikansio URL, jotta voit käyttää omaa palvelintasi oletuksena uusien topikkien tilaamisessa ja/tai aiheiden jakamisessa.</string>
<string name="user_dialog_password_hint_edit">Salasana (ei voi muuttaa, jos jätetään tyhjäksi)</string>
<string name="settings_advanced_record_logs_summary_disabled">Ota logaus käyttöön, jotta voit jakaa lokit myöhemmin diagnosoidaksesi ongelmia.</string>
<string name="main_action_mode_delete_dialog_message">Lopetetaanko valittujen aiheiden tilaus ja poistetaanko kaikki ilmoitukset pysyvästi \?</string>
<string name="notification_dialog_muted_until_toast_message">Ilmoituset hiljennetty %1$s asti</string>
<string name="share_title">Jaa</string>
<string name="refresh_message_error">Ei voitu päivittää %1$d tilausta
\n
\n%2$s</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Käytä JSON HTTP:n kautta muodostaaksesi yhteyden palvelimeen. Tämä menetelmä on testattu, mutta se voi kuluttaa enemmän akkua.</string>
<string name="settings_advanced_export_logs_copied_logs">Logit kopioitu leikkelepöydälle</string>
<string name="channel_subscriber_notification_noinstant_text_six">Tilattu kuuteen topikkiin</string>
<string name="detail_settings_notifications_instant_summary_on">Ilmoitukset toimitetaan välittömästi. kuluttaa enemmän akkua.</string>
<string name="detail_test_title">Testi: Voit asettaa otsikon, jos haluat.</string>
<string name="settings_advanced_connection_protocol_summary_ws">Käytä WebSocketsia yhteyden muodostamiseen palvelimeen. Tämä on suositeltu tapa, mutta se voi vaatia lisämäärityksiä välityspalvelimessasi.</string>
<string name="settings_notifications_auto_download_summary_smaller_than_x">Lataa automaattisesti liitteet %1$s saakka</string>
<string name="settings_notifications_auto_download_10m">Jos tiedoston koko on alle 10 MB</string>
<string name="settings_advanced_export_logs_scrub_dialog_button_ok">OK</string>
<string name="settings_advanced_connection_protocol_title">Yhteys protokolla</string>
<string name="notification_popup_action_cancel">Peruuta</string>
<string name="settings_backup_restore_restore_title">Palauta tiedostosta</string>
<string name="share_content_image_error">Kuvaa ei voi lukea %1$s</string>
<string name="notification_dialog_cancel">Peruuta</string>
<string name="main_banner_battery_button_dismiss">Hylkää</string>
<string name="detail_menu_copy_url">Kopioi topikin osoite</string>
<string name="settings_notifications_min_priority_low">Matalan prioriteetin ylittävät</string>
<string name="detail_settings_notifications_dedicated_channels_title">Mukautetut ilmoitusasetukset</string>
<string name="main_menu_settings_title">Asetukset</string>
<string name="share_topic_title">Jaettu</string>
<string name="detail_settings_appearance_icon_set_summary">Aseta kuvake, joka näytetään ilmoituksissa</string>
<string name="main_how_to_intro">Napsauta + luodaksesi topikin tai tilataksesi sen. Tämän jälkeen saat ilmoituksia laitteellesi, kun lähetät viestejä PUT- tai POST-yhteydellä.</string>
<string name="main_action_bar_title">Tilatut topikit</string>
<string name="detail_menu_notifications_enabled">Ilmoitukset päälle</string>
<string name="settings_backup_restore_backup_entry_settings_only">Vain asetukset</string>
<string name="detail_item_cannot_save">Ei voida tallentaa liitettä: %1$s</string>
<string name="detail_item_snack_undo">Kumoa</string>
<string name="settings_backup_restore_backup_successful">Varmuuskopio luotu</string>
<string name="detail_settings_appearance_display_name_default_summary">%1$s (oletus)</string>
<string name="channel_subscriber_notification_noinstant_text_three">Tilattu kolmeen topikkiin</string>
<string name="channel_subscriber_notification_noinstant_text_five">Tilattu viiteen topikkiin</string>
<string name="main_action_mode_menu_unsubscribe">Lopeta tilaus</string>
<string name="add_dialog_login_description">Tämä topikki vaatii kirjautumisen. Kirjoita käyttäjätunnus ja salasana.</string>
<string name="settings_general_users_prefs_user_used_by_many">Käytetty topikeissa %1$s</string>
<string name="detail_settings_global_setting_title">Käytä globaalia asetusta</string>
<string name="settings_notifications_auto_download_summary_never">Älä koskaan lataa automaattisesti liitteitä</string>
<string name="detail_item_download_info_deleted_expired">Poistettu, linkki vanhentunut</string>
<string name="detail_item_menu_save_file">Tallenna tiedosto</string>
<string name="main_menu_docs_title">Lue dokumentaatiota</string>
<string name="settings_notifications_auto_delete_summary_one_day">Poista ilmoitukset yhden päivän jälkeen</string>
<string name="refresh_message_no_results">Kaikki päivitetty</string>
<string name="detail_item_download_info_not_downloaded_expired">Ei ladattu, linkki vanhentunut</string>
<string name="settings_advanced_record_logs_summary_enabled">Logaus (jopa 1 000 merkintää) laitteeseen…</string>
<string name="settings_notifications_auto_delete_summary_three_days">Poista ilmoitukset 3 päivän jälkeen</string>
<string name="channel_subscriber_notification_instant_text_one">Tilattu yhteen välittömään topikkiin</string>
<string name="share_content_file_text">Tedoston on jaettu sinulle</string>
<string name="main_banner_websocket_button_dismiss">Hylkää</string>
<string name="add_dialog_base_urls_dropdown_clear">Poista palvelimen URL</string>
<string name="detail_action_mode_delete_dialog_message">Poista valitut tilaukset välittömästi \?</string>
<string name="detail_settings_about_topic_url_title">Topikin URL</string>
<string name="add_dialog_title">Liity topikkin</string>
<string name="add_dialog_button_back">Takaisin</string>
<string name="settings_advanced_header">Kehittyneet</string>
<string name="settings_notifications_auto_delete_summary_three_months">Poista ilmoitukset kolmen kuukauden jälkeen</string>
<string name="notification_popup_file">%1$s
\nTiedosto: %2$s</string>
<string name="settings_notifications_muted_until_forever">Ilmoitukset mykistetty, kunnes niitä jatketaan</string>
<string name="detail_how_to_example">Esimerkki (käytä curl):<br/><tt>$ curl -d \"Hei\" %1$s</tt></string>
<string name="detail_settings_appearance_icon_set_title">Kuvake</string>
<string name="detail_instant_delivery_disabled">Välitön lähetys pois</string>
<string name="channel_subscriber_notification_instant_text_four">Tilattu neljään välittömään topikkiin</string>
<string name="settings_notifications_auto_download_1m">Jos tiedoston koko on alle 1 MB</string>
<string name="detail_item_download_info_download_failed_expired">Lataus epäonnistunut, linkki vanhentunut</string>
<string name="detail_settings_notifications_instant_summary_off">Ilmoitukset toimitetaan Firebasella. Toimitus saattaa viivästyä, mutta kuluttaa vähemmän akkua.</string>
<string name="detail_settings_notifications_open_channels_summary">Älä häiritse (DND) ohitus, äänet jne.</string>
<string name="detail_test_message_error_unauthorized_user">Viestiä ei voi lähettää: Käyttäjällä \"%1$s\" ei ole oikeuksia.</string>
<string name="notification_dialog_title">Hiljennetyt ilmoitukset</string>
<string name="settings_notifications_min_priority_summary_x_or_higher">Näytä ilmoitukset jos täkeys on %1$d (%2$s) tai enemmän</string>
<string name="settings_advanced_export_logs_entry_copy_scrubbed">Kopioi leikkelepöydälle (sensuroitu)</string>
<string name="settings_advanced_export_logs_copied_url">Logit tallennettu ja URL kopioitu</string>
<string name="settings_advanced_export_logs_title">Kopioi/tallenna logit</string>
<string name="detail_settings_appearance_icon_remove_summary">Tämän topikin ilmoituksissa näkyvä kuvake</string>
<string name="settings_backup_restore_backup_failed">Varmuuskopio epäonnistunut: %1$s</string>
<string name="detail_test_message_error_too_large">Viestiä ei voi lähettää: Liite on liian suuri.</string>
<string name="settings_notifications_priority_low">matala</string>
<string name="channel_subscriber_notification_noinstant_text_one">Tilattu yhteen topikkiin</string>
<string name="settings_about_version_format">ntfy %1$s (%2$s)</string>
<string name="settings_notifications_auto_download_summary_always">Lataa automaattisesti liitteet</string>
<string name="user_dialog_title_edit">Muokkaa käyttäjää</string>
<string name="settings_backup_restore_restore_successful">Palautus onnistui</string>
<string name="settings_notifications_auto_delete_one_week">jälkeen seitsemän päivän</string>
<string name="settings_backup_restore_restore_failed">Palautus epäonnistui: %1$s</string>
<string name="settings_notifications_header">Ilmoitukset</string>
<string name="detail_test_message">Tämä on testi-ilmoitus ntfy Android -sovelluksesta. Sillä on prioriteettitaso %1$d. Jos lähetät toisen, se voi näyttää erilaiselta.</string>
<string name="detail_settings_appearance_icon_remove_title">Kuvake (napauta poistaaksesi)</string>
<string name="share_suggested_topics">Ehdotetut topikit</string>
<string name="detail_settings_appearance_display_name_message">Aseta tälle topikille mukautettu näyttönimi. Jätä tyhjäksi oletuksena (%1$s).</string>
<string name="detail_settings_appearance_icon_error_saving">Ei voida tallentaa kuvaketta %1$s</string>
<string name="detail_settings_notifications_dedicated_channels_summary_off">Oletusasetusten käyttäminen (äänet, Älä häiritse -tilan ohitus jne.)</string>
<string name="detail_item_menu_cancel">Peruuta lataus</string>
<string name="channel_notifications_high_name">Korkea tärkeys</string>
<string name="settings_advanced_record_logs_title">Nauhoitetut logit</string>
<string name="settings_notifications_insistent_max_priority_title">Pidä hälytykset korkeimmalla tasolla</string>
<string name="settings_notifications_min_priority_max">Vain maksimi ja ylittävät</string>
<string name="settings_about_header">About</string>
<string name="main_menu_donate_title">Lahjoita 💸</string>
<string name="notification_dialog_8h">8 tuntia</string>
<string name="detail_deep_link_subscribed_toast_message">Topikki %1$s tilattu</string>
<string name="user_dialog_username_hint">Käyttäjätunnus</string>
<string name="detail_menu_unsubscribe">Lopeta tilaus</string>
<string name="settings_notifications_auto_download_always">Lataa automaattisesti kaikki</string>
<string name="detail_menu_settings">Tilauksien asetukset</string>
<string name="settings_notifications_auto_delete_never">Ei koskaan</string>
<string name="main_item_status_unified_push">%1$s (Yleis Push)</string>
<string name="detail_item_tags">Tagit %1$s</string>
<string name="main_item_status_text_one">%1$d Huomautus</string>
</resources>

View file

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="channel_notifications_low_name">Priorité basse</string>
<string name="channel_notifications_default_name">Priorité par défaut</string>
<string name="channel_notifications_low_name">Notifications (priorité basse)</string>
<string name="channel_notifications_default_name">Notifications (priorité normale)</string>
<string name="channel_subscriber_service_name">Abonnement</string>
<string name="channel_subscriber_notification_instant_text_two">Abonné à deux sujets à réception instantanée</string>
<string name="channel_subscriber_notification_instant_text_four">Abonné à quatre sujets à réception instantanée</string>
<string name="channel_subscriber_notification_instant_text_more">Abonné à %1$d sujets à réception instantanée</string>
<string name="channel_subscriber_notification_instant_text_two">Abonné à deux sujets de livraison instantanée</string>
<string name="channel_subscriber_notification_instant_text_four">Abonné à quatre sujets de livraison instantanée</string>
<string name="channel_subscriber_notification_instant_text_more">Abonné à %1$d sujets de livraison instantanée</string>
<string name="channel_subscriber_notification_noinstant_text">Abonné aux sujets</string>
<string name="channel_subscriber_notification_noinstant_text_one">Abonné à un sujet</string>
<string name="channel_subscriber_notification_noinstant_text_four">Abonné à quatre sujets</string>
@ -19,11 +19,12 @@
<string name="main_item_date_yesterday">hier</string>
<string name="main_add_button_description">Ajout d\'abonnement</string>
<string name="main_how_to_link">Des instructions détaillées sont disponible sur ntfy.sh et dans la documentation.</string>
<string name="main_banner_battery_text">L\'optimisation de la batterie devrait être désactivée pour l\'application afin d\'éviter des problèmes de réception de notifications.</string>
<string name="main_banner_websocket_button_remind_later">Demander plus tard</string>
<string name="main_banner_websocket_button_dismiss">Ignorer</string>
<string name="main_banner_battery_text">L\'optimisation de la pile devrait être désactivée pour l\'application afin d\'éviter des problèmes de réception de notifications.</string>
<string name="main_banner_json_stream_button_remind_later">Demander plus tard</string>
<string name="main_banner_json_stream_button_dismiss">Ignorer</string>
<string name="main_banner_json_stream_button_learn_more">En apprendre plus</string>
<string name="add_dialog_topic_name_hint">Nom de sujet, ex. : phils_alerts</string>
<string name="add_dialog_instant_delivery">Réception instantanée en mode économie d\'énergie</string>
<string name="add_dialog_instant_delivery">Livraison instantanée en mode somnolence</string>
<string name="add_dialog_button_cancel">Annuler</string>
<string name="add_dialog_button_subscribe">Abonner</string>
<string name="add_dialog_button_back">Retour</string>
@ -42,7 +43,7 @@
<string name="detail_item_menu_download">Télécharger un fichier</string>
<string name="detail_item_menu_cancel">Annuler le téléchargement</string>
<string name="detail_item_menu_copy_url">Copier l\'URL</string>
<string name="detail_item_cannot_open_url">Incapable d\'ouvrir l\'URL : %1$s</string>
<string name="detail_item_cannot_open_click_url">Incapable d\'ouvrir l\'URL : %1$s</string>
<string name="detail_item_download_info_not_downloaded">pas téléchargé</string>
<string name="detail_item_download_info_deleted">supprimé</string>
<string name="detail_item_download_info_download_failed">échec du téléchargement</string>
@ -52,15 +53,15 @@
<string name="detail_menu_unsubscribe">Désabonner</string>
<string name="detail_action_mode_delete_dialog_permanently_delete">Supprimer définitivement</string>
<string name="detail_action_mode_delete_dialog_message">Supprimer définitivement la ou les notification(s) sélectionnée(s) \?</string>
<string name="channel_subscriber_notification_instant_text_one">Abonné à un sujet à réception instantanée</string>
<string name="channel_notifications_max_name">Priorité maximale</string>
<string name="channel_notifications_min_name">Priorité minimale</string>
<string name="channel_notifications_high_name">Priorité élevée</string>
<string name="channel_subscriber_notification_instant_text_one">Abonné à un sujet de livraison instantanée</string>
<string name="channel_notifications_max_name">Notifications (priorité maximale)</string>
<string name="channel_notifications_min_name">Notifications (priorité minimale)</string>
<string name="channel_notifications_high_name">Notifications (priorité élevée)</string>
<string name="channel_subscriber_notification_title">Écoute les notifications entrantes</string>
<string name="channel_subscriber_notification_instant_text">Abonné aux sujets à réception instantanée</string>
<string name="channel_subscriber_notification_instant_text_three">Abonné à trois sujets à réception instantanée</string>
<string name="channel_subscriber_notification_instant_text">Abonné aux sujets de livraison instantanée</string>
<string name="channel_subscriber_notification_instant_text_three">Abonné à trois sujets de livraison instantanée</string>
<string name="refresh_message_no_results">Tout est à jour</string>
<string name="main_menu_notifications_disabled_forever">Notifications en sourdine</string>
<string name="main_menu_notifications_disabled_forever">Notifications interrompues</string>
<string name="channel_subscriber_notification_noinstant_text_two">Abonné à deux sujets</string>
<string name="main_menu_notifications_enabled">Notifications activées</string>
<string name="channel_subscriber_notification_noinstant_text_three">Abonné à trois sujets</string>
@ -69,7 +70,7 @@
\n
\n%2$s</string>
<string name="main_action_bar_title">Sujets abonnés</string>
<string name="main_menu_notifications_disabled_until">Notifications en sourdine jusqu\'à %1$s</string>
<string name="main_menu_notifications_disabled_until">Notifications interrompues jusqu\'à %1$s</string>
<string name="main_menu_settings_title">Paramètres</string>
<string name="main_menu_rate_title">Évaluer l\'application ⭐</string>
<string name="main_action_mode_menu_unsubscribe">Désabonner</string>
@ -82,13 +83,14 @@
<string name="main_how_to_intro">Cliquez le + pour créer ou vous abonner à un sujet. Ensuite, vous recevrez des notifications sur votre appareil lors de l\'envoi de messages par PUT ou POST.</string>
<string name="main_unified_push_toast">Cet abonnement est géré par %1$s à l\'aide de UnifiedPush</string>
<string name="main_banner_battery_button_remind_later">Demander plus tard</string>
<string name="main_banner_json_stream_text">Changez pour les WebSockets dans Paramètres / «Protocole de connexion» maintenant pour assurer que vous puissiez communiquer avec votre serveur ntfy hébergé par vous-même après le mois de juin 2022.</string>
<string name="add_dialog_description_below">Les sujets ne peuvent pas être protégés par mot de passe, choisissez donc un nom difficile à deviner. Une fois abonné, vous pourrez PUT/POST des notifcations.</string>
<string name="add_dialog_title">Abonner au sujet</string>
<string name="add_dialog_error_connection_failed">La connexion a échouée : %1$s</string>
<string name="detail_no_notifications_text">Vous n\'avez pas encore reçu de notifications pour ce sujet.</string>
<string name="share_content_file_text">Un fichier a été partagé avec vous</string>
<string name="add_dialog_use_another_server">Utiliser un serveur différent</string>
<string name="add_dialog_use_another_server_description">Entrez les URLs de service ci-dessous pour vous abonner aux sujets de serveurs différents.</string>
<string name="add_dialog_use_another_server_description">Entrez les URLs de serveurs ci-dessous pour vous abonner aux sujets de serveurs différents.</string>
<string name="add_dialog_instant_delivery_description">S\'assure que les messages sont envoyés immédiatement, même si l\'appareil est inactif.</string>
<string name="add_dialog_foreground_description">La livraison instantanée est toujours active pour les serveurs autres que %1$s.</string>
<string name="add_dialog_button_login">Se connecter</string>
@ -105,7 +107,7 @@
<string name="detail_test_message">Ceci est une notification de test depuis l\'application Android ntfy. Elle a une priorité de niveau %1$d. Si vous en envoyez une autre, elle pourrait avoir un apparence différente.</string>
<string name="detail_test_message_error_unauthorized_anon">Incapable d\'envoyer le message : La publication anonyme est interdite.</string>
<string name="detail_test_message_error_unauthorized_user">Incapable d\'envoyer le message : L\'utilisateur \"%1$s\" n\'est pas autorisé.</string>
<string name="detail_test_message_error_too_large">Impossible d\'envoyer le message : La pièce jointe est trop lourde.</string>
<string name="detail_test_message_error_too_large">Incapable d\'envoyer le message : La pièce jointe est trop large.</string>
<string name="detail_instant_delivery_enabled">Livraison instantanée active</string>
<string name="detail_item_snack_deleted">Notification supprimée</string>
<string name="detail_item_menu_copy_url_copied">L\'URL a été copiée dans le presse-papier</string>
@ -125,10 +127,10 @@
<string name="detail_item_download_info_downloading_x_percent">%1$d%% téléchargé</string>
<string name="detail_item_download_info_deleted_expired">supprimé, lien expiré</string>
<string name="detail_item_download_info_deleted_expires_x">supprimé, expire le %1$s</string>
<string name="detail_menu_notifications_disabled_until">Notifications en sourdine jusqu\'à %1$s</string>
<string name="detail_menu_notifications_disabled_until">Notifications interrompues jusqu\'à %1$s</string>
<string name="detail_item_download_info_download_failed_expires_x">échec du téléchargement, expire le %1$s</string>
<string name="share_content_image_error">Incapable de lire l\'image : %1$s</string>
<string name="detail_menu_notifications_disabled_forever">Notifications en sourdine</string>
<string name="detail_menu_notifications_disabled_forever">Notifications interrompues</string>
<string name="detail_menu_disable_instant">Désactiver la livraison instantanée</string>
<string name="detail_menu_notifications_enabled">Notifications activées</string>
<string name="detail_menu_enable_instant">Activer la livraison instantanée</string>
@ -152,11 +154,11 @@
<string name="share_topic_title">Partager</string>
<string name="share_suggested_topics">Sujets suggérés</string>
<string name="share_successful">Message publié</string>
<string name="notification_dialog_title">Mettre en sourdine les notifications</string>
<string name="notification_dialog_title">Mettre en pause les notifications</string>
<string name="notification_dialog_cancel">Annuler</string>
<string name="notification_dialog_save">Enregistrer</string>
<string name="notification_dialog_muted_forever_toast_message">Notifications en sourdine</string>
<string name="notification_dialog_muted_until_toast_message">Notifications en sourdine jusqu\'à %1$s</string>
<string name="notification_dialog_muted_forever_toast_message">Notifications en pause</string>
<string name="notification_dialog_muted_until_toast_message">Notifications en pause jusqu\'à %1$s</string>
<string name="notification_dialog_show_all">Afficher toutes les notifications</string>
<string name="notification_dialog_30min">30 minutes</string>
<string name="notification_dialog_1h">1 heure</string>
@ -176,12 +178,12 @@
\nFichier : %2$s, échec du téléchargement</string>
<string name="settings_title">Paramètres</string>
<string name="settings_notifications_header">Notifications</string>
<string name="settings_notifications_muted_until_forever">Notifications en sourdine jusqu\'à réactivation</string>
<string name="settings_notifications_muted_until_x">Notifications en sourdine jusqu\'à %1$s</string>
<string name="settings_notifications_muted_until_forever">Notifications en pause jusqu\'à réactivation</string>
<string name="settings_notifications_muted_until_x">Notifications en pause jusqu\'à %1$s</string>
<string name="settings_notifications_min_priority_title">Priorité minimale</string>
<string name="notification_popup_file_downloading">Téléchargement de %1$s, %2$d%%
\n%3$s</string>
<string name="settings_notifications_muted_until_title">Mettre en sourdine les notifications</string>
<string name="settings_notifications_muted_until_title">Mettre en pause les notifications</string>
<string name="settings_notifications_muted_until_show_all">Affiche toutes les notifications</string>
<string name="settings_notifications_min_priority_low">Priorité faible ou supérieure</string>
<string name="settings_notifications_auto_download_summary_never">Ne jamais télécharger automatiquement les pièces jointes</string>
@ -255,7 +257,7 @@
<string name="settings_about_version_format">ntfy %1$s (%2$s)</string>
<string name="user_dialog_title_add">Ajouter utilisateur</string>
<string name="user_dialog_title_edit">Éditer utilisateur</string>
<string name="user_dialog_base_url_hint">URL du service</string>
<string name="user_dialog_base_url_hint">URL du serveur</string>
<string name="user_dialog_username_hint">Nom d\'utilisateur</string>
<string name="user_dialog_button_add">Ajouter utilisateur</string>
<string name="user_dialog_button_cancel">Annuler</string>
@ -269,7 +271,7 @@
<string name="settings_notifications_priority_min">min</string>
<string name="settings_general_users_prefs_title">Utilisateurs</string>
<string name="settings_general_dark_mode_summary_system">Utilisé le thème système</string>
<string name="settings_notifications_min_priority_summary_any">Affichage de toutes les notifications</string>
<string name="settings_notifications_min_priority_summary_any">Toutes les notifications</string>
<string name="settings_notifications_priority_default">défaut</string>
<string name="settings_notifications_auto_delete_summary_three_days">Supprimer automatiquement les notifications après 3 jours</string>
<string name="settings_notifications_auto_delete_one_day">Après un jour</string>
@ -286,8 +288,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 é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_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_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>
@ -298,51 +300,4 @@
\n%1$s
\n
\nLes mots de passe sont nettoyés, mais ne sont pas listés ici.</string>
<string name="detail_deep_link_subscribed_toast_message">Abonné au sujet %1$s</string>
<string name="settings_notifications_channel_prefs_summary">Ignorer « ne pas déranger », sons, etc.</string>
<string name="notification_popup_user_action_failed">%1$s a échoué : %2$s</string>
<string name="settings_notifications_channel_prefs_title">Paramètres du canal</string>
<string name="channel_subscriber_notification_noinstant_text_six">Abonné à six sujets</string>
<string name="detail_settings_notifications_instant_title">Réception instantanée</string>
<string name="channel_subscriber_notification_noinstant_text_five">Abonné à cinq sujets</string>
<string name="detail_settings_notifications_instant_summary_off">Les notifications sont transmises à l\'aide de Firebase. La réception peut être retardée, mais consomme moins de batterie.</string>
<string name="detail_settings_appearance_icon_remove_summary">Icône affichée pour les notifications de ce sujet</string>
<string name="channel_subscriber_notification_instant_text_six">Abonné à six sujets à réception instantanée</string>
<string name="channel_subscriber_notification_instant_text_five">Abonné à cinq sujets à réception instantanée</string>
<string name="detail_settings_appearance_header">Apparence</string>
<string name="detail_settings_appearance_icon_remove_title">Icône de souscription (toucher pour retirer)</string>
<string name="detail_settings_appearance_icon_error_saving">Impossible d\'enregistrer l\'icône : %1$s</string>
<string name="detail_settings_notifications_instant_summary_on">Les notifications sont reçues instantanément. Requiert un service en premier plan et consomme plus de batterie.</string>
<string name="detail_settings_appearance_icon_set_title">Icône d\'abonnement</string>
<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>
<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>
<string name="detail_settings_appearance_display_name_title">Nom d\'affichage</string>
<string name="detail_settings_appearance_display_name_default_summary">%1$s</string>
<string name="detail_settings_appearance_display_name_message">Mettre un nom d\'affichage personnalisé pour cette souscription. Laisse ce champ vide pour mettre la valeur par défaut (%1$s).</string>
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">Copié au Presse-papier</string>
<string name="detail_settings_about_header">À propos</string>
<string name="detail_settings_about_topic_url_title">URL du sujet</string>
<string name="channel_notifications_group_default_name">Défaut</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_enabled">Conserver les notifications</string>
<string name="main_menu_donate_title">Faire un don 💸</string>
<string name="detail_item_cannot_open_apk">Les applications ne peuvent plus être installées. Veuillez les télécharger via un navigateur. Voir le ticket #531 pour plus de détails.</string>
<string name="settings_notifications_insistent_max_priority_title">Conserver les notifications avec une priorité maximale</string>
<string name="detail_settings_notifications_dedicated_channels_title">Paramètres personnalisés de la notification</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_disabled">Affiche les notifications une fois seulement</string>
<string name="detail_settings_notifications_dedicated_channels_summary_on">Utilisation de paramètres personnalisés pour cet abonnement</string>
<string name="detail_settings_notifications_dedicated_channels_summary_off">Utilisation des paramètres par défaut (sons, ignorer « ne pas déranger », etc.)</string>
<string name="settings_notifications_insistent_max_priority_summary_disabled">Les notifications avec une priorité maximale ne sont affichées qu\'une seule fois</string>
<string name="detail_settings_notifications_open_channels_title">Configurer les paramètres de la notification</string>
<string name="settings_notifications_insistent_max_priority_summary_enabled">Les notifications avec une priorité maximale sont affichées jusqu\'à ce qu\'elles soient rejetées</string>
<string name="detail_settings_notifications_open_channels_summary">Ignorer « ne pas déranger », sons, etc.</string>
<string name="settings_advanced_unifiedpush_summary_enabled">ntfy agira comme un distributeur UnifiedPush</string>
<string name="settings_advanced_unifiedpush_summary_disabled">ntfy n\'agira pas comme un distributeur UnifiedPush</string>
<string name="settings_advanced_unifiedpush_title">Activer le \"UnifiedPush\"</string>
<string name="eos_settings_enable_title">Activer le distributeur</string>
<string name="eos_settings_enable_description">Cela permet aux applications tierces de recevoir des notifications UnifiedPush</string>
</resources>

View file

@ -1,346 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="channel_notifications_min_name">Prioridade Min</string>
<string name="channel_notifications_low_name">Prioridade baixa</string>
<string name="channel_notifications_default_name">Prioridade por defecto</string>
<string name="channel_notifications_high_name">Prioridade alta</string>
<string name="channel_notifications_max_name">Prioridade Máx</string>
<string name="channel_subscriber_service_name">Servizo de subscrición</string>
<string name="channel_notifications_group_default_name">Por defecto</string>
<string name="channel_subscriber_notification_title">Agardando por notificacións entrantes</string>
<string name="channel_subscriber_notification_instant_text">Subscrita ao envío instantáneo de asuntos</string>
<string name="channel_subscriber_notification_instant_text_one">Subscrita ao envío instantáneo dun asunto</string>
<string name="channel_subscriber_notification_instant_text_two">Subscrita ao envío instantáneo de dous asuntos</string>
<string name="channel_subscriber_notification_instant_text_three">Subscrita ao envío instantáneo de tres asuntos</string>
<string name="channel_subscriber_notification_instant_text_four">Subscrita ao envío instantáneo de catro asuntos</string>
<string name="channel_subscriber_notification_instant_text_five">Subscrita ao envío instantáneo de cinco asuntos</string>
<string name="channel_subscriber_notification_instant_text_six">Subscrita ao envío instantáneo de seis asuntos</string>
<string name="channel_subscriber_notification_instant_text_more">Subscrita ao envío instantáneo de %1$d asuntos</string>
<string name="channel_subscriber_notification_noinstant_text">Subscrita a asuntos</string>
<string name="channel_subscriber_notification_noinstant_text_six">Subscrita a seis asuntos</string>
<string name="channel_subscriber_notification_noinstant_text_more">Subscrita a %1$d asuntos</string>
<string name="refresh_message_error">Non se actualizaron %1$d subscricións
\n
\n%2$s</string>
<string name="refresh_message_error_one">Non se actualizou a subscrición: %1$s</string>
<string name="main_action_bar_title">Asuntos subscritos</string>
<string name="main_menu_notifications_enabled">Notificacións activadas</string>
<string name="main_menu_notifications_disabled_forever">Notificacións acaladas</string>
<string name="main_menu_notifications_disabled_until">Notificacións acaladas ata %1$s</string>
<string name="main_menu_settings_title">Axustes</string>
<string name="main_menu_report_bug_title">Informar dun fallo</string>
<string name="main_menu_docs_title">Ler documentación</string>
<string name="main_menu_rate_title">Valorar a app ⭐</string>
<string name="main_menu_donate_title">Doar 💸</string>
<string name="main_action_mode_menu_unsubscribe">Retirar subscrición</string>
<string name="main_action_mode_delete_dialog_message">Retirar a subscrición ao(s) asunto(s) seleccionado(s) e eliminar definitivamente tódalas notificacións\?</string>
<string name="main_action_mode_delete_dialog_permanently_delete">Eliminar definitivamente</string>
<string name="main_action_mode_delete_dialog_cancel">Cancelar</string>
<string name="main_item_status_text_one">%1$d notificación</string>
<string name="main_item_status_text_not_one">%1$d notificacións</string>
<string name="main_item_status_reconnecting">reconectando…</string>
<string name="channel_subscriber_notification_noinstant_text_one">Subscrita a un asunto</string>
<string name="channel_subscriber_notification_noinstant_text_two">Subscrita a dous asuntos</string>
<string name="channel_subscriber_notification_noinstant_text_three">Subscrita a tres asuntos</string>
<string name="channel_subscriber_notification_noinstant_text_four">Subscrita a catro asuntos</string>
<string name="refresh_message_result">%1$d notificación(s) recibida(s)</string>
<string name="channel_subscriber_notification_noinstant_text_five">Subscrita a cinco asuntos</string>
<string name="refresh_message_no_results">Todo ao día</string>
<string name="main_item_status_unified_push">%1$s (UnifiedPush)</string>
<string name="main_item_date_yesterday">onte</string>
<string name="main_how_to_intro">Preme no + para crear ou subscribirte a un tema. Posteriormente recibirás notificacións no teu dispositivo cando se envían mensaxes a través de PUT ou POST.</string>
<string name="main_unified_push_toast">Esta subscrición está xestionada por %1$s a través de UnifiedPush</string>
<string name="main_how_to_link">Instruccións detalladas dispoñibles en ntfy.sh, e na documentación.</string>
<string name="main_add_button_description">Engadir subscrición</string>
<string name="main_no_subscriptions_text">Semella que aínda non tes ningunha subscrición.</string>
<string name="main_banner_battery_text">A optimización da batería debe estar desactivada para a app para evitar problemas coas notificacións.</string>
<string name="main_banner_battery_button_remind_later">Preguntar máis tarde</string>
<string name="main_banner_battery_button_dismiss">Desbotar</string>
<string name="main_banner_battery_button_fix_now">Arranxar agora</string>
<string name="main_banner_websocket_text">O cambio a WebSockets é o xeito recomendado para conectar co servidor, pode mellorar a vida da batería, pero pode requerir <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">configuración adicional no teu proxy</a>. Pódese cambiar nos Axustes.</string>
<string name="main_banner_websocket_button_remind_later">Preguntar máis tarde</string>
<string name="main_banner_websocket_button_dismiss">Desbotar</string>
<string name="main_banner_websocket_button_enable_now">Activar agora</string>
<string name="add_dialog_title">Subscribir ao tema</string>
<string name="add_dialog_description_below">Os temas poden non estar protexidos con contrasinal, escolle un nome dificil de adiviñar. Unha vez subscrito, podes PUT/POST notificacións.</string>
<string name="add_dialog_topic_name_hint">Nome do tema, ex. alertas_xoan</string>
<string name="add_dialog_use_another_server">Usar outro servidor</string>
<string name="add_dialog_use_another_server_description">Escribe o URL do servizo para subscribirte a temas doutros servidores.</string>
<string name="add_dialog_instant_delivery">Entrega inmediata en modo silencioso</string>
<string name="add_dialog_instant_delivery_description">Asegura que as mensaxes se entregan de xeito inmediato, incluso se o dispositivo non está activo.</string>
<string name="add_dialog_foreground_description">A entrega inmediata sempre está activa para hóspedes diferentes a %1$s.</string>
<string name="add_dialog_button_cancel">Cancelar</string>
<string name="add_dialog_button_subscribe">Subscribir</string>
<string name="add_dialog_button_back">Atrás</string>
<string name="add_dialog_button_login">Acceder</string>
<string name="add_dialog_error_connection_failed">Fallou a conexión: %1$s</string>
<string name="add_dialog_login_title">Require iniciar sesión</string>
<string name="add_dialog_login_description">Este tema require que inicies sesión. Escribe as túas credenciais.</string>
<string name="add_dialog_login_username_hint">Identificador</string>
<string name="add_dialog_login_password_hint">Contrasinal</string>
<string name="add_dialog_login_error_not_authorized">Fallou o acceso. A usuaria %1$s non está autorizada.</string>
<string name="add_dialog_login_new_user">Nova usuaria</string>
<string name="add_dialog_base_urls_dropdown_choose">Escribe URL do servizo</string>
<string name="add_dialog_base_urls_dropdown_clear">Limpar URL do servizo</string>
<string name="detail_no_notifications_text">Aínda non recibiches notificacións deste tema.</string>
<string name="detail_how_to_example">Exemplo (usando curl): <br/><tt>$ curl -d \"Ola\" %1$s</tt></string>
<string name="detail_how_to_link">Tes instruccións polo miúdo en ntfy.sh, e na documentación.</string>
<string name="detail_clear_dialog_message">Eliminar todas as notificacións neste tema\?</string>
<string name="detail_clear_dialog_permanently_delete">Eliminar permanentemente</string>
<string name="detail_clear_dialog_cancel">Cancelar</string>
<string name="detail_delete_dialog_message">Retirar subscrición ao tema e eliminar todas as notificacións recibidas\?</string>
<string name="detail_delete_dialog_permanently_delete">Eliminar permanentemente</string>
<string name="detail_delete_dialog_cancel">Cancelar</string>
<string name="detail_test_title">Proba: podes poñerlle un título se queres.</string>
<string name="detail_test_message">Esta é unha notificación de proba desde a app ntfy Android. Ten nivel %1$d de prioridade. Se envías outra, podería ser diferente.</string>
<string name="detail_test_message_error">Non se enviou a mensaxe: %1$s</string>
<string name="detail_test_message_error_unauthorized_anon">Non se enviou a mensaxe: Non está permitida a publicación anónima.</string>
<string name="detail_test_message_error_unauthorized_user">Non se enviou a mensaxe: A usuaria \"%1$s\" non ten autorización.</string>
<string name="detail_test_message_error_too_large">Non se enviou a mensaxe: O adxunto é demasiado grande.</string>
<string name="detail_copied_to_clipboard_message">Copiado ao portapapeis</string>
<string name="detail_instant_delivery_enabled">Entrega inmediata activada</string>
<string name="detail_instant_delivery_disabled">Entrega inmediata desactivada</string>
<string name="detail_deep_link_subscribed_toast_message">Subscrita ao tema %1$s</string>
<string name="detail_item_tags">Etiquetas: %1$s</string>
<string name="detail_item_snack_deleted">Notificación eliminada</string>
<string name="detail_item_snack_undo">Desfacer</string>
<string name="detail_item_menu_open">Abrir ficheiro</string>
<string name="detail_item_menu_delete">Eliminar ficheiro</string>
<string name="detail_item_menu_download">Descargar ficheiro</string>
<string name="detail_item_menu_cancel">Cancelar descarga</string>
<string name="detail_item_menu_save_file">Gardar ficheiro</string>
<string name="detail_item_menu_copy_url">Copiar URL</string>
<string name="detail_item_menu_copy_url_copied">URL copiado ao portapapeis</string>
<string name="detail_item_menu_copy_contents">Copiar notificación</string>
<string name="detail_item_menu_copy_contents_copied">Notificación copiada ao portapapeis</string>
<string name="detail_item_saved_successfully">Gardado como \"%1$s\" no cartafol \"Descargas\"</string>
<string name="detail_how_to_intro">Enviar notificacións a este tema, simplemente envía con PUT ou POST ao URL do tema.</string>
<string name="detail_item_cannot_download">Non se pode abrir ou descargar o adxunto. A ligazón caducou e non se atopa un ficheiro local.</string>
<string name="detail_item_cannot_open">Non se pode abrir: %1$s</string>
<string name="detail_item_cannot_open_not_found">Non se pode abrir o adxunto: pode que fose eliminado, ou ningunha app instalada pode abrir o ficheiro.</string>
<string name="detail_item_cannot_open_url">Non se pode abrir URL: %1$s</string>
<string name="detail_item_cannot_open_apk">Xa non poden instalarse as apps. Descarga desde un navegador. Ver detalles no issue #531.</string>
<string name="detail_item_cannot_save">Non se pode gardar o adxunto: %1$s</string>
<string name="detail_item_cannot_delete">Non se pode borrar o adxunto: %1$s</string>
<string name="detail_item_download_failed">Non se puido descargar o adxunto: %1$s</string>
<string name="detail_item_download_info_not_downloaded">non descargado</string>
<string name="detail_item_download_info_downloading_x_percent">%1$d%% descargado</string>
<string name="detail_item_download_info_deleted_expires_x">eliminado, a ligazón caduca o %1$s</string>
<string name="detail_item_download_info_download_failed">fallou a descarga</string>
<string name="detail_item_download_info_download_failed_expired">fallou a descarga, caducou a ligazón</string>
<string name="detail_item_download_info_download_failed_expires_x">fallou a descarga, a ligazón caduca %1$s</string>
<string name="detail_menu_notifications_enabled">Notificación activas</string>
<string name="detail_menu_notifications_disabled_forever">Notificacións acaladas</string>
<string name="detail_menu_enable_instant">Activar entrega inmediata</string>
<string name="detail_item_download_info_not_downloaded_expires_x">non descargado, caduca %1$s</string>
<string name="detail_item_download_info_not_downloaded_expired">non descargado, caducou a ligazón</string>
<string name="detail_item_download_info_deleted">eliminado</string>
<string name="detail_item_download_info_deleted_expired">eliminado, caducou a ligazón</string>
<string name="detail_menu_notifications_disabled_until">Notificacións acaladas ate %1$s</string>
<string name="detail_menu_disable_instant">Desactivar o envío instantáneo</string>
<string name="detail_menu_test">Enviar notificación de proba</string>
<string name="detail_action_mode_delete_dialog_message">Eliminar a notificación(s) permanentemente\?</string>
<string name="detail_action_mode_delete_dialog_permanently_delete">Eliminar permanentemente</string>
<string name="detail_action_mode_delete_dialog_cancel">Cancelar</string>
<string name="detail_settings_title">Axustes da subscrición</string>
<string name="share_title">Compartir</string>
<string name="share_content_title">Vista previa da mensaxe</string>
<string name="share_content_image_error">Non se pode ler a imaxe: %1$s</string>
<string name="share_content_file_text">Compartiron un ficheiro contigo</string>
<string name="share_content_text_hint">Engadir aquí o contido para compartir</string>
<string name="share_content_image_text">Compartiron unha imaxe contigo</string>
<string name="share_content_file_error">Non se pode ler a info do ficheiro: %1$s</string>
<string name="share_topic_title">Compartir con</string>
<string name="share_suggested_topics">Temas suxeridos</string>
<string name="share_successful">Mensaxe publicada</string>
<string name="notification_dialog_cancel">Cancelar</string>
<string name="notification_dialog_save">Gardar</string>
<string name="notification_dialog_enabled_toast_message">Reactivadas as notificacións</string>
<string name="notification_popup_file_download_successful">%1$s
\nFicheiro: %2$s, descargado</string>
<string name="notification_popup_file_download_failed">%1$s
\nFicheiro: %2$s, fallou a descarga</string>
<string name="notification_popup_user_action_failed">Fallo en %1$s: %2$s</string>
<string name="settings_title">Axutes</string>
<string name="settings_notifications_header">Notificacións</string>
<string name="notification_dialog_title">Acalar notificacións</string>
<string name="settings_notifications_muted_until_title">Acalar notificacións</string>
<string name="settings_notifications_muted_until_show_all">Mostrando todas as notificacións</string>
<string name="settings_notifications_min_priority_min">Calquera prioridade</string>
<string name="settings_notifications_min_priority_low">Prioridade baixa ou superior</string>
<string name="settings_notifications_min_priority_default">Prioridade por defecto e superior</string>
<string name="detail_menu_copy_url">Copiar enderezo do tema</string>
<string name="detail_menu_clear">Limpar todas as notificacións</string>
<string name="detail_menu_settings">Axustes da subscrición</string>
<string name="detail_menu_unsubscribe">Retirar subscrición</string>
<string name="detail_action_mode_menu_copy">Copiar</string>
<string name="detail_action_mode_menu_delete">Eliminar</string>
<string name="share_menu_send">Compartir</string>
<string name="notification_dialog_muted_forever_toast_message">Notificacións acaladas</string>
<string name="notification_dialog_muted_until_toast_message">Acalar notificacións %1$s</string>
<string name="notification_dialog_show_all">Mostrar todas as notificacións</string>
<string name="notification_dialog_30min">30 minutos</string>
<string name="notification_dialog_1h">1 hora</string>
<string name="notification_dialog_2h">2 horas</string>
<string name="notification_dialog_forever">Ata reactivalas</string>
<string name="notification_dialog_8h">8 horas</string>
<string name="notification_dialog_tomorrow">Ata mañán</string>
<string name="notification_popup_action_open">Abrir</string>
<string name="notification_popup_action_browse">Buscar</string>
<string name="notification_popup_action_download">Descargar</string>
<string name="notification_popup_action_cancel">Cancelar</string>
<string name="notification_popup_file">%1$s
\nFicheiro: %2$s</string>
<string name="notification_popup_file_downloading">Descargando %1$s, %2$d%%
\n%3$s</string>
<string name="settings_notifications_muted_until_forever">Notificacións acaladas ata retomalas</string>
<string name="settings_notifications_muted_until_x">Notificacións acaladas ate %1$s</string>
<string name="settings_notifications_min_priority_title">Prioridade mínima</string>
<string name="settings_notifications_min_priority_summary_any">Mostrando todas as notificacións</string>
<string name="settings_notifications_min_priority_summary_x_or_higher">Mostrar notificacións se a prioridade é %1$d (%2$s) ou superior</string>
<string name="settings_notifications_min_priority_summary_max">Mostrar notificacións se a prioridade é 5 (máx.)</string>
<string name="settings_notifications_min_priority_high">Alta prioridade ou superior</string>
<string name="settings_notifications_min_priority_max">Só máxima prioridade</string>
<string name="settings_notifications_priority_min">mínima</string>
<string name="settings_notifications_priority_low">baixa</string>
<string name="settings_notifications_channel_prefs_title">Axustes da canle</string>
<string name="settings_notifications_priority_default">por defecto</string>
<string name="settings_notifications_priority_high">alta</string>
<string name="settings_notifications_priority_max">máxima</string>
<string name="settings_notifications_channel_prefs_summary">Obviar Non Molestar (DND), sons, etc.</string>
<string name="settings_notifications_auto_download_title">Descargar adxuntos</string>
<string name="settings_notifications_auto_download_summary_always">Descarga automática dos adxuntos</string>
<string name="settings_notifications_auto_download_summary_never">Non descargar automaticamente os adxuntos</string>
<string name="settings_notifications_auto_download_summary_smaller_than_x">Descarga automática dos adxuntos ata %1$s</string>
<string name="settings_notifications_auto_download_never">Non descargar nunca automaticamente</string>
<string name="settings_notifications_auto_delete_summary_one_week">Eliminar automaticamene as notificacións após unha semana</string>
<string name="settings_notifications_auto_delete_summary_one_month">Eliminar automaticamente as notificacións após un mes</string>
<string name="settings_notifications_auto_delete_summary_three_months">Eliminar automaticamente as notificacións após 3 meses</string>
<string name="settings_notifications_auto_delete_never">Nunca</string>
<string name="settings_notifications_auto_delete_one_day">Após un día</string>
<string name="settings_notifications_insistent_max_priority_summary_enabled">Manter as alertas da prioridade máis alta ata que se desboten</string>
<string name="settings_notifications_insistent_max_priority_summary_disabled">Notificar as alertas da máxima prioridade só unha vez</string>
<string name="settings_general_header">Xeral</string>
<string name="settings_general_default_base_url_title">Servidor por defecto</string>
<string name="settings_general_default_base_url_default_summary">%1$s (por defecto)</string>
<string name="settings_general_users_title">Xestionar usuarias</string>
<string name="settings_general_users_summary">Engade/elimina usuarias dos temas protexidos</string>
<string name="settings_general_users_prefs_title">Usuarias</string>
<string name="settings_general_users_prefs_user_not_used">Non utilizado por ningún tema</string>
<string name="settings_general_users_prefs_user_used_by_one">Usado polo tema %1$s</string>
<string name="settings_general_users_prefs_user_add">Engadir usuarias</string>
<string name="settings_general_users_prefs_user_add_title">Engadir nova usuaria</string>
<string name="settings_general_users_prefs_user_add_summary">Crear unha nova usuaria para un novo servidor</string>
<string name="settings_general_dark_mode_title">Modo escuro</string>
<string name="settings_general_dark_mode_summary_system">Seguir o establecido no sistema</string>
<string name="settings_general_dark_mode_summary_light">Modo claro activado</string>
<string name="settings_general_dark_mode_summary_dark">Modo escuro activado. Es un morcego\?</string>
<string name="settings_general_dark_mode_entry_system">Seguir ao sistema</string>
<string name="settings_general_dark_mode_entry_light">Modo claro</string>
<string name="settings_general_dark_mode_entry_dark">Modo escuro</string>
<string name="settings_backup_restore_header">Copia e Restablecemento</string>
<string name="settings_backup_restore_backup_title">Copia de apoio nun ficheiro</string>
<string name="settings_backup_restore_backup_summary">Exportar configuración, notificacións e usuarias</string>
<string name="settings_backup_restore_backup_entry_everything">Todo</string>
<string name="settings_backup_restore_backup_entry_everything_no_users">Todo, menos as usuarias</string>
<string name="settings_backup_restore_backup_entry_settings_only">Só os axustes</string>
<string name="settings_backup_restore_backup_successful">Copia creada</string>
<string name="settings_backup_restore_backup_failed">Fallou a copia: %1$s</string>
<string name="settings_notifications_auto_download_always">Descargar todo automaticamente</string>
<string name="settings_notifications_auto_download_100k">Se inferior a 100 kB</string>
<string name="settings_notifications_auto_download_500k">Se inferior a 500 kB</string>
<string name="settings_notifications_auto_download_1m">Se inferior a 1 MB</string>
<string name="settings_notifications_auto_download_5m">Se inferior a 5 MB</string>
<string name="settings_notifications_auto_download_10m">Se inferior a 10 MB</string>
<string name="settings_notifications_auto_download_50m">Se inferior a 50 MB</string>
<string name="settings_notifications_auto_delete_title">Eliminar notificacións</string>
<string name="settings_notifications_auto_delete_summary_never">Non eliminar nunca automaticamente as notificacións</string>
<string name="settings_notifications_auto_delete_summary_one_day">Eliminar automaticamente as notificacións após un día</string>
<string name="settings_notifications_auto_delete_summary_three_days">Eliminar automaticamente as notificacións após 3 días</string>
<string name="settings_notifications_auto_delete_three_days">Após 3 días</string>
<string name="settings_notifications_auto_delete_one_week">Após unha semana</string>
<string name="settings_notifications_auto_delete_one_month">Após un mes</string>
<string name="settings_notifications_auto_delete_three_months">Após 3 meses</string>
<string name="settings_notifications_insistent_max_priority_title">Manter as alertas da prioridade máis alta</string>
<string name="settings_general_default_base_url_message">Escribe o enderezo URL raíz do teu servidor para usar o servidor propio por defecto cando te subscribas a novos temas e/ou compartas os temas.</string>
<string name="settings_general_users_prefs_user_used_by_many">Usado polos temas %1$s</string>
<string name="settings_advanced_broadcast_summary_enabled">As app poden recibir notificacións entrantes como difusións</string>
<string name="settings_advanced_broadcast_summary_disabled">As app non poden recibir notificacións entrantes como difusións</string>
<string name="settings_backup_restore_restore_failed">Fallou o restablecemento: %1$s</string>
<string name="settings_advanced_header">Avanzado</string>
<string name="settings_advanced_broadcast_title">Mensaxes de difusión</string>
<string name="settings_advanced_export_logs_scrub_dialog_text">Estes temas e nomes de servidor serán substituídos por nomes de froita, así podes compartilos sen problema:
\n
\n%1$s
\n
\nOs contrasinais son anulados, pero non aparecen aquí.</string>
<string name="settings_advanced_export_logs_scrub_dialog_button_ok">OK</string>
<string name="settings_advanced_connection_protocol_summary_ws">Usar WebSockets para conectar co servidor. Este é o método recomendado, pero podería precisar configuración adicional no teu proxy.</string>
<string name="settings_advanced_connection_protocol_entry_jsonhttp">Fluxo JSON sobre HTTP</string>
<string name="settings_advanced_connection_protocol_entry_ws">WebSockets</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Usar un fluxo JSON sobre HTTP para conectar co servidor. Este método é robusto, pero podería consumir máis batería.</string>
<string name="settings_about_version_copied_to_clipboard_message">Copiado ao portapapeis</string>
<string name="detail_settings_notifications_instant_title">Entrega inmediata</string>
<string name="settings_about_header">Acerca de</string>
<string name="settings_about_version_title">Versión</string>
<string name="settings_about_version_format">ntfy %1$s (%2$s)</string>
<string name="detail_settings_notifications_instant_summary_off">Notificacións entregadas usando Firebase. A entrega podería sufrir demora, pero consume menos batería.</string>
<string name="detail_settings_notifications_dedicated_channels_title">Axustes personais de notificación</string>
<string name="detail_settings_notifications_dedicated_channels_summary_on">Usar axustes personais para esta subscrición</string>
<string name="detail_settings_notifications_dedicated_channels_summary_off">Usar axustes por defecto (sons, obviar Non Molestar, etc.)</string>
<string name="detail_settings_notifications_open_channels_summary">Obviar Non Molestar (DND), sons, etc.</string>
<string name="detail_settings_notifications_open_channels_title">Configurar axustes da notificación</string>
<string name="detail_settings_appearance_icon_error_saving">Non se gardou a icona: %1$s</string>
<string name="detail_settings_appearance_display_name_title">Nome mostrado</string>
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">Copiado ao portapapeis</string>
<string name="settings_backup_restore_restore_title">Restablecer desde ficheiro</string>
<string name="settings_backup_restore_restore_summary">Importar configuración, notificacións e usuarias</string>
<string name="settings_backup_restore_restore_successful">Restablecemento correcto</string>
<string name="settings_advanced_unifiedpush_summary_enabled">nfty actuará como distribuidora UnifiedPush</string>
<string name="settings_advanced_unifiedpush_summary_disabled">nfty non actuará como distribuidora UnifiedPush</string>
<string name="settings_advanced_record_logs_title">Gravar rexistros</string>
<string name="settings_advanced_record_logs_summary_enabled">Gravando (ata 1000 entradas) no dispositivo…</string>
<string name="settings_advanced_record_logs_summary_disabled">Activar rexistro, así poderás compartir os rexistros para diagnosticar problemas.</string>
<string name="settings_advanced_clear_logs_title">Limpar rexistros</string>
<string name="settings_advanced_export_logs_title">Copiar/subir rexistros</string>
<string name="settings_advanced_export_logs_summary">Copia os rexistros ao portapapeis, ou súbeos a nopaste.net (propiedade de ntfy). Os nomes de servidor e temas poden agocharse, as notificacións non.</string>
<string name="settings_advanced_export_logs_entry_copy_original">Copiar ao portapapeis</string>
<string name="settings_advanced_export_logs_entry_copy_scrubbed">Copiar ao portapapeis (censurado)</string>
<string name="settings_advanced_export_logs_entry_upload_original">Subir e copiar ligazón</string>
<string name="settings_advanced_export_logs_entry_upload_scrubbed">Subir e copiar ligazón (censurado)</string>
<string name="settings_advanced_export_logs_copied_logs">Rexistros copiados ao portapapeis</string>
<string name="settings_advanced_export_logs_uploading">Subindo o rexistro …</string>
<string name="settings_advanced_export_logs_copied_url">Rexistros subidos e URL copiado</string>
<string name="settings_advanced_export_logs_error_uploading">Non se puido subir o rexistro: %1$s</string>
<string name="settings_advanced_export_logs_scrub_dialog_empty">Non se editaron temas/servidores. Non tes ningunha subscrición\?</string>
<string name="settings_advanced_clear_logs_summary">Eliminar os rexistros anteriores e volver a comezar</string>
<string name="settings_advanced_clear_logs_deleted_toast">Rexistros eliminados</string>
<string name="settings_advanced_connection_protocol_title">Protocolo de conexión</string>
<string name="detail_settings_notifications_instant_summary_on">As notificacións entregaranse inmediatamente. Require un servizo en segundo plano e consume máis batería.</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_enabled">Seguir avisando</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_disabled">Avisar só unha vez</string>
<string name="detail_settings_appearance_header">Aspecto</string>
<string name="detail_settings_appearance_icon_set_title">Icona da subscrición</string>
<string name="detail_settings_appearance_icon_set_summary">Establecer a icona a mostrar na notificación</string>
<string name="detail_settings_appearance_icon_remove_title">Icona da subscrición (toca para eliminar)</string>
<string name="detail_settings_appearance_icon_remove_summary">Icona mostrada na notificación deste tema</string>
<string name="user_dialog_button_add">Engadir usuaria</string>
<string name="detail_settings_appearance_display_name_message">Establece o nome para mostrar para esta subscrición. Deixa en branco para valor por defecto (%1$s).</string>
<string name="detail_settings_appearance_display_name_default_summary">%1$s (por defecto)</string>
<string name="detail_settings_global_setting_title">Usar axuste global</string>
<string name="detail_settings_global_setting_suffix">usando o axuste global</string>
<string name="detail_settings_about_header">Acerca de</string>
<string name="detail_settings_about_topic_url_title">URL do tema</string>
<string name="user_dialog_title_add">Engadir usuaria</string>
<string name="user_dialog_button_cancel">Cancelar</string>
<string name="user_dialog_button_delete">Eliminar usuaria</string>
<string name="user_dialog_button_save">Gardar</string>
<string name="settings_advanced_unifiedpush_title">Activar UnifiedPush</string>
<string name="user_dialog_title_edit">Editar usuaria</string>
<string name="user_dialog_description_add">Podes engadir aquí unha usuaria. Todos os temas do servidor indicado usarán esta usuaria.</string>
<string name="user_dialog_description_edit">Podes editar as credenciais da usuaria seleccionada, ou eliminala.</string>
<string name="user_dialog_base_url_hint">URL do servizo</string>
<string name="user_dialog_username_hint">Identificador</string>
<string name="user_dialog_password_hint_add">Contrasinal</string>
<string name="user_dialog_password_hint_edit">Contrasinal (baleiro para non cambiar)</string>
</resources>

View file

@ -1,92 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="channel_notifications_default_name">महत्वपूर्ण</string>
<string name="channel_notifications_high_name">ज्यादा महत्वपूर्ण</string>
<string name="channel_notifications_max_name">बहुत ज्यादा महत्वपूर्ण</string>
<string name="channel_notifications_group_default_name">साधारण</string>
<string name="channel_notifications_min_name">बहुत कम महत्त्व</string>
<string name="channel_notifications_low_name">कम महत्व</string>
<string name="channel_subscriber_service_name">सदस्यता सेवा</string>
<string name="channel_subscriber_notification_title">आने वाली सूचनाओं को सुनना</string>
<string name="channel_subscriber_notification_instant_text_two">दो त्वरित वितरण विषय का जानना</string>
<string name="channel_subscriber_notification_instant_text_three">तीन त्वरित वितरण विषय का जानना</string>
<string name="channel_subscriber_notification_instant_text_four">चार त्वरित वितरण विषय का जानना</string>
<string name="channel_subscriber_notification_instant_text">त्वरित वितरण विषय का जानना</string>
<string name="channel_subscriber_notification_instant_text_one">एक त्वरित वितरण विषय का जानना</string>
<string name="channel_subscriber_notification_instant_text_more">%1$d त्वरित वितरण विषयों का जानना</string>
<string name="channel_subscriber_notification_noinstant_text">विषयों का जानना</string>
<string name="channel_subscriber_notification_instant_text_six">छह त्वरित वितरण विषयों का जानना</string>
<string name="channel_subscriber_notification_instant_text_five">पाँच त्वरित वितरण विषयों का जानना</string>
<string name="add_dialog_login_password_hint">पासवर्ड</string>
<string name="add_dialog_login_error_not_authorized">लॉगिन विफल। उपयोगकर्ता %1$s अधिकृत नहीं है।</string>
<string name="add_dialog_foreground_description">%1$s के अलावा अन्य मेज़बानों के लिए तत्काल डिलीवरी हमेशा चालू रहती है।</string>
<string name="add_dialog_login_new_user">नया उपयोगकर्ता</string>
<string name="add_dialog_login_title">लॉगिन आवश्यक</string>
<string name="main_menu_rate_title">एप को रेट करें</string>
<string name="main_item_status_text_not_one">%1$d सूचनाएं</string>
<string name="refresh_message_result">%1$d सूचना(एं ) प्राप्त</string>
<string name="detail_no_notifications_text">इस विषय पर आपको अभी तक कोई सूचना नहीं मिली है।</string>
<string name="channel_subscriber_notification_noinstant_text_two">दो विषयों की सदस्यता</string>
<string name="main_no_subscriptions_text">ऐसा लगता है कि आपके पास अभी तक कोई सदस्यता नहीं है।</string>
<string name="channel_subscriber_notification_noinstant_text_more">%1$d विषयों की सदस्यता</string>
<string name="main_banner_battery_button_fix_now">अब ठीक करें</string>
<string name="main_menu_notifications_enabled">सूचनाएं चालू</string>
<string name="main_menu_notifications_disabled_forever">सूचनाएं मौन</string>
<string name="main_banner_websocket_button_remind_later">बाद में पूछें</string>
<string name="main_add_button_description">सदस्यता जोड़ें</string>
<string name="main_action_mode_delete_dialog_permanently_delete">स्थायी रूप से मिटाएं</string>
<string name="add_dialog_description_below">सम्भवतः विषय पासवर्ड से सुरक्षित नहीं हो सकते हैं, इसलिए ऐसा नाम चुनें जिसका अनुमान लगाना कठिन हो। एक बार सदस्यता लेने के बाद, आप सूचनाएं PUT/POST कर सकते हैं।</string>
<string name="main_item_status_reconnecting">फिर से जुड़ रहा है…</string>
<string name="add_dialog_instant_delivery_description">यह सुनिश्चित करता है कि डिवाइस निष्क्रिय होने पर भी संदेश तुरंत वितरित हो।</string>
<string name="main_menu_notifications_disabled_until">सूचनाएं मौन जब तक %1$s</string>
<string name="main_banner_websocket_button_enable_now">अब चालू करें</string>
<string name="main_item_date_yesterday">बीता हुआ कल</string>
<string name="main_banner_battery_button_remind_later">बाद में पूछें</string>
<string name="main_how_to_link">विस्तृत निर्देश ntfy.sh और दस्तावेज़ों में उपलब्ध हैं।</string>
<string name="channel_subscriber_notification_noinstant_text_four">चार विषयों की सदस्यता</string>
<string name="add_dialog_use_another_server_description">दूसरे सर्वर्स के विषयों की सदस्यता लेने के लिए सर्विस URLs दर्ज करें।</string>
<string name="main_unified_push_toast">यह सदस्यता UnifiedPush के माध्यम से %1$s द्वारा प्रबंधित की जाती है</string>
<string name="main_menu_report_bug_title">खराबी रिपोर्ट करें</string>
<string name="add_dialog_button_cancel">रद्द</string>
<string name="add_dialog_topic_name_hint">विषय का नाम, उदा. phils_alerts</string>
<string name="add_dialog_error_connection_failed">कनेक्शन विफल हुआ: %1$s</string>
<string name="main_action_mode_delete_dialog_cancel">रद्द करना</string>
<string name="add_dialog_button_subscribe">सदस्यता लें</string>
<string name="add_dialog_button_login">लॉग इन करें</string>
<string name="refresh_message_error_one">सदस्यताएं रिफ्रेश नहीं हो सकी: %1$s</string>
<string name="add_dialog_login_username_hint">यूजरनेम</string>
<string name="add_dialog_use_another_server">दूसरे सर्वर का प्रयोग करें</string>
<string name="add_dialog_base_urls_dropdown_choose">सर्विस URL का चयन करें</string>
<string name="add_dialog_instant_delivery">Doze मोड में तुरंत डिलीवरी</string>
<string name="main_banner_battery_text">अधिसूचना वितरण समस्याओं से बचने के लिए ऐप के लिए बैटरी ऑप्टिमाइजेशन बंद होना चाहिए।</string>
<string name="main_action_mode_delete_dialog_message">चयनित विषय(विषयों) से सदस्यता समाप्त करें और सभी सूचनाएं स्थायी रूप से हटा दें\?</string>
<string name="refresh_message_error">%1$d सदस्यताएं रिफ्रेश नहीं हो सकी
\n
\n%2$s</string>
<string name="channel_subscriber_notification_noinstant_text_six">छह विषयों की सदस्यता</string>
<string name="main_banner_battery_button_dismiss">रद्द करें</string>
<string name="main_menu_settings_title">सेटिंग्स</string>
<string name="main_how_to_intro">किसी विषय को बनाने या उसकी सदस्यता लेने के लिए + पर क्लिक करें। बाद में PUT या POST के माध्यम से संदेश भेजते समय आपको अपने डिवाइस पर सूचनाएं प्राप्त होती हैं।</string>
<string name="main_action_bar_title">सदस्यता लिए गए विषय</string>
<string name="channel_subscriber_notification_noinstant_text_three">तीन विषयों की सदस्यता</string>
<string name="channel_subscriber_notification_noinstant_text_five">पांच विषयों की सदस्यता</string>
<string name="main_action_mode_menu_unsubscribe">सदस्यता रद्द</string>
<string name="add_dialog_login_description">इस विषय के लिए आपको लॉगिन करना होगा। कृपया यूजरनेम और पासवर्ड टाइप करें।</string>
<string name="main_menu_docs_title">दस्तावेज़ पढ़ें</string>
<string name="refresh_message_no_results">सब कुछ नवीनतम जानकारी से युक्त</string>
<string name="main_banner_websocket_button_dismiss">रद्द करें</string>
<string name="add_dialog_base_urls_dropdown_clear">सर्विस URL हटाएं</string>
<string name="add_dialog_title">विषय की सदस्यता लें</string>
<string name="add_dialog_button_back">पीछे जाएं</string>
<string name="channel_subscriber_notification_noinstant_text_one">एक विषय की सदस्यता</string>
<string name="main_menu_donate_title">दान करें</string>
<string name="main_item_status_text_one">%1$d सूचना</string>
<string name="detail_clear_dialog_cancel">रद्द करें</string>
<string name="detail_delete_dialog_cancel">रद्द करें</string>
<string name="detail_how_to_link">विस्तृत निर्देश ntfy.sh पर और डॉक्स में उपलब्ध हैं।</string>
<string name="detail_clear_dialog_permanently_delete">स्थायी रूप से हटाएं</string>
<string name="detail_how_to_intro">इस विषय पर सूचनाएं भेजने के लिए, बस विषय URL पर PUT या POST करें।</string>
<string name="detail_how_to_example">उदाहरण (curl का उपयोग करके):<br/><tt>$curl -d \"नमस्कार\"%1$s</tt></string>
<string name="detail_clear_dialog_message">इस विषय की सभी सूचनाएँ हटाएँ?</string>
<string name="main_banner_websocket_text">WebSockets पर स्विच करना आपके सर्वर से कनेक्ट करने का अनुशंसित तरीका है, और बैटरी जीवन में सुधार कर सकता है, लेकिन आपके <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">proxy में अतिरिक्त कॉन्फ़िगरेशन</a> की आवश्यकता हो सकती है। इसे सेटिंग्स में टॉगल किया जा सकता है।</string>
</resources>

View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="channel_notifications_min_name">Obavijesti (minimalni prioritet)</string>
<string name="channel_notifications_low_name">Obavijesti (niski prioritet)</string>
<string name="channel_notifications_default_name">Obavijesti (standardni prioritet)</string>
<string name="channel_notifications_high_name">Obavijesti (visoki prioritet)</string>
<string name="channel_notifications_max_name">Obavijesti (maksimalni prioritet)</string>
</resources>

View file

@ -1,136 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="main_action_mode_delete_dialog_permanently_delete">Végleges törlés</string>
<string name="channel_subscriber_notification_instant_text_one">Feliratkozva egy azonnal kézbesített témára</string>
<string name="channel_subscriber_notification_instant_text_five">Feliratkozva öt azonnal kézbesített témára</string>
<string name="channel_subscriber_notification_instant_text_six">Feliratkozva hat azonnal kézbesített témára</string>
<string name="channel_subscriber_notification_instant_text_more">Feliratkozva %1$d azonnal kézbesített témára</string>
<string name="channel_subscriber_notification_noinstant_text">Feliratkozott témák</string>
<string name="channel_subscriber_notification_noinstant_text_one">Feliratkozva egy témára</string>
<string name="main_menu_notifications_disabled_forever">Értesítések némítva</string>
<string name="main_menu_notifications_disabled_until">Értesítések némítva %1$s-ig</string>
<string name="main_menu_settings_title">Beállítások</string>
<string name="main_item_status_text_not_one">%1$d értesítés</string>
<string name="main_item_status_reconnecting">Újra-csatlakozás …</string>
<string name="main_item_status_unified_push">%1$s (ÖsszesítettKüldés)</string>
<string name="main_add_button_description">Feliratkozás hozzáadása</string>
<string name="main_no_subscriptions_text">Úgy néz ki hogy még nincsen egy feliratkozás sem.</string>
<string name="main_how_to_intro">Kattintson a + ra hogy létrehozzon vagy feliratkozzon egy témára. Aztán mikor PUT vagy POST-al küld üzeneteket, értesítéseket kap a készülékén.</string>
<string name="channel_notifications_min_name">Minimum prioritás</string>
<string name="channel_notifications_low_name">Alacsony prioritás</string>
<string name="channel_notifications_default_name">Alapértelmezett prioritás</string>
<string name="channel_notifications_max_name">Maximum prioritás</string>
<string name="channel_notifications_high_name">Magas prioritás</string>
<string name="channel_subscriber_service_name">Feliratkozó Szolgálat</string>
<string name="channel_subscriber_notification_title">Bejövő üzenetek fogadása</string>
<string name="channel_subscriber_notification_instant_text">Feliratkozva azonnal kézbesített témákra</string>
<string name="channel_subscriber_notification_instant_text_two">Feliratkozva két azonnal kézbesített témára</string>
<string name="channel_subscriber_notification_instant_text_three">Feliratkozva három azonnal kézbesített témára</string>
<string name="channel_subscriber_notification_instant_text_four">Feliratkozva négy azonnal kézbesített témára</string>
<string name="channel_subscriber_notification_noinstant_text_six">Feliratkozva hat témára</string>
<string name="channel_subscriber_notification_noinstant_text_five">Feliratkozva öt témára</string>
<string name="channel_subscriber_notification_noinstant_text_four">Feliratkozva négy témára</string>
<string name="channel_subscriber_notification_noinstant_text_three">Feliratkozva három témára</string>
<string name="channel_subscriber_notification_noinstant_text_more">Feliratkozva %1$d témára</string>
<string name="channel_subscriber_notification_noinstant_text_two">Feliratkozva két témára</string>
<string name="main_menu_docs_title">Dokumentáció olvasása</string>
<string name="main_action_mode_menu_unsubscribe">Leiratkozás</string>
<string name="refresh_message_result">%1$d üzenet érkezett</string>
<string name="refresh_message_no_results">Minden a legfrissebb verzió</string>
<string name="refresh_message_error">Nem lehetett %1$d feliratkozást frissíteni
\n
\n%2$s</string>
<string name="refresh_message_error_one">Feliratkozást frissítése nem lehetséges: %1$s</string>
<string name="main_menu_notifications_enabled">Értesítések bekapcsolva</string>
<string name="main_action_bar_title">Feliratkozott témák</string>
<string name="main_menu_report_bug_title">Hiba jelentése</string>
<string name="main_item_date_yesterday">tegnap</string>
<string name="main_menu_rate_title">Applikáció értékelése ⭐</string>
<string name="main_action_mode_delete_dialog_message">Leiratkozás a kiválasztott témá(k)-ról és végleges törlése minden üzenetnek\?</string>
<string name="main_item_status_text_one">%1$d értesítés</string>
<string name="main_action_mode_delete_dialog_cancel">Mégse</string>
<string name="channel_notifications_group_default_name">Alapértelmezett</string>
<string name="main_menu_donate_title">Adomány 💸</string>
<string name="main_banner_websocket_button_dismiss">Bezár</string>
<string name="add_dialog_instant_delivery_description">Garantálja az azonnali üzenetküldést, akkor is, ha az eszköz inaktív.</string>
<string name="add_dialog_foreground_description">Az azonnali üzenetküldés mindig bekapcsolva a %1$s címen kívül.</string>
<string name="add_dialog_button_login">Bejelentkezés</string>
<string name="add_dialog_error_connection_failed">Kapcsolódási hiba: %1$s</string>
<string name="add_dialog_login_title">Bejelentkezés szükséges</string>
<string name="add_dialog_login_description">Ehhez a témához be kell jelentkezni. Kérem add meg a felhasználó nevedet és jelszavadat!</string>
<string name="add_dialog_login_username_hint">Felhasználó</string>
<string name="add_dialog_login_new_user">Új felhasználó</string>
<string name="detail_how_to_link">Részletes leírás elérhető a ntfy.sh oldalon és a dokumentációban.</string>
<string name="detail_clear_dialog_permanently_delete">Végleges törlés</string>
<string name="detail_clear_dialog_cancel">Mégse</string>
<string name="detail_delete_dialog_message">Leiratkozás a témáról és az összes értesítés törlése\?</string>
<string name="detail_delete_dialog_cancel">Mégse</string>
<string name="detail_test_title">Teszt: Beállíthatsz témát, ha szeretnél.</string>
<string name="detail_item_snack_deleted">Értesítés törölve</string>
<string name="detail_item_menu_download">Fájl letöltése</string>
<string name="detail_test_message_error_unauthorized_user">Nem sikerült az üzenetet elküldeni: A \"%1$s\" felhasználó jogosultságai nem megfelelőek.</string>
<string name="detail_item_menu_copy_url_copied">URL a vágólapra másolva</string>
<string name="detail_item_menu_copy_contents">Értesítés másolása</string>
<string name="add_dialog_title">Feliratokozás a témára</string>
<string name="main_banner_websocket_button_enable_now">Engedélyezés most</string>
<string name="add_dialog_instant_delivery">Azonnali küldés dózis módban</string>
<string name="add_dialog_login_password_hint">Jelszó</string>
<string name="add_dialog_login_error_not_authorized">Bejelentkezési hiba. A %1$s felhasználó nem azonosítható.</string>
<string name="detail_clear_dialog_message">Töröljük az összes értesítést ebben a témában\?</string>
<string name="detail_test_message_error_too_large">Nem sikerült az üzenetet elküldeni: A csatolmány túl nagy.</string>
<string name="detail_deep_link_subscribed_toast_message">Feliratkozva a %1$s témára</string>
<string name="detail_item_menu_copy_contents_copied">Értesítés a vágólapra másolva</string>
<string name="main_banner_battery_button_remind_later">Később</string>
<string name="main_how_to_link">Részletes leírás elérhető a ntfy.sh oldalon és a dokumentációban.</string>
<string name="main_banner_battery_text">Az akkumulátor optimalizáció kikapcsolása javasolt az értesítési problémák elkerülésére.</string>
<string name="main_banner_websocket_button_remind_later">Később</string>
<string name="main_banner_battery_button_dismiss">Bezár</string>
<string name="main_banner_battery_button_fix_now">Javítás most</string>
<string name="add_dialog_description_below">A témák nem feltétlenül jelszóval védettek, ezért válassz olyan nevet, amelyet nehéz kitalálni! Ha feliratkoztál, akkor küldhetsz PUT/POST értesítéseket.</string>
<string name="add_dialog_topic_name_hint">Téma neve, pl. tibi_jelzesei</string>
<string name="add_dialog_use_another_server">Használj másik szervert</string>
<string name="add_dialog_use_another_server_description">Add meg a szolgáltatók címét alább, hogy más szerveren futó témákra is feliratkozhass.</string>
<string name="add_dialog_button_subscribe">Feliratkozás</string>
<string name="add_dialog_button_back">Vissza</string>
<string name="detail_no_notifications_text">Még nem érkezett értesítés ebben a témában.</string>
<string name="detail_delete_dialog_permanently_delete">Végleges törlés</string>
<string name="detail_test_message_error_unauthorized_anon">Nem sikerült az üzenetet elküldni: A névtelen publikálás nem engedélyezett.</string>
<string name="detail_copied_to_clipboard_message">Vágólapra másolva</string>
<string name="detail_instant_delivery_enabled">Azonnali küldés bekapcsolva</string>
<string name="detail_instant_delivery_disabled">Azonnali küldés kikapcsolva</string>
<string name="detail_item_menu_open">Fájl megnyitása</string>
<string name="detail_item_menu_delete">Fájl törlése</string>
<string name="detail_item_menu_copy_url">URL másolása</string>
<string name="detail_item_menu_cancel">Letöltés leállítása</string>
<string name="detail_item_menu_save_file">Fájl mentése</string>
<string name="detail_item_cannot_download">Nem sikerült a melléklet megnyitása vagy letöltése. A link lejárt és a helyi fájl nem található.</string>
<string name="detail_item_cannot_open">A melléklet nem nyitható meg: %1$s</string>
<string name="detail_item_cannot_open_not_found">A melléklet nem nyitható meg: A fájl törölve lett, vagy nincs megfelelő alkalmazás telepítve a megnyitáshoz.</string>
<string name="detail_item_saved_successfully">Mentve \"%1$s\" néven a \"Downloads\" mappába</string>
<string name="detail_item_cannot_open_url">Az URL nem nyitható meg: %1$s</string>
<string name="add_dialog_button_cancel">Mégse</string>
<string name="detail_test_message">Ez egy teszt értesítés az Android ntfy alkalmazásból. A beállított prioritás %1$d. Ha küldesz egy újat nem feltétlenül így fog kinézni.</string>
<string name="detail_test_message_error">Nem sikerült az üzenetet elküldeni: %1$s</string>
<string name="detail_item_snack_undo">Visszavon</string>
<string name="detail_item_download_info_deleted">törölve</string>
<string name="detail_menu_unsubscribe">Leiratkozás</string>
<string name="detail_action_mode_menu_copy">Másolás</string>
<string name="detail_action_mode_menu_delete">Törlés</string>
<string name="share_menu_send">Megosztás</string>
<string name="notification_dialog_30min">30 perc</string>
<string name="notification_dialog_1h">1 óra</string>
<string name="notification_popup_action_cancel">Mégse</string>
<string name="detail_action_mode_delete_dialog_cancel">Mégse</string>
<string name="notification_dialog_save">Mentés</string>
<string name="notification_dialog_show_all">Összes értesítés mutatása</string>
<string name="notification_dialog_muted_forever_toast_message">Értesítések lenémítva</string>
<string name="notification_dialog_2h">2 óra</string>
<string name="notification_dialog_8h">8 óra</string>
<string name="settings_title">Beállítások</string>
<string name="detail_item_download_info_downloading_x_percent">%1$d%% letöltve</string>
<string name="share_title">Megosztás</string>
<string name="notification_dialog_title">Értesítések némítása</string>
<string name="notification_dialog_cancel">Mégse</string>
<string name="settings_notifications_header">Értesítések</string>
<string name="settings_notifications_muted_until_title">Értesítések némítása</string>
</resources>

View file

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="channel_subscriber_notification_noinstant_text">Berlangganan ke topik</string>
<string name="channel_notifications_default_name">Prioritas bawaan</string>
<string name="channel_notifications_max_name">Prioritas maks</string>
<string name="channel_notifications_min_name">Prioritas min</string>
<string name="channel_notifications_low_name">Prioritas rendah</string>
<string name="channel_notifications_default_name">Notifikasi (prioritas default)</string>
<string name="channel_notifications_max_name">Notifikasi (prioritas maks)</string>
<string name="channel_notifications_min_name">Notifikasi (prioritas min)</string>
<string name="channel_notifications_low_name">Notifikasi (prioritas rendah)</string>
<string name="channel_subscriber_service_name">Layanan Langganan</string>
<string name="channel_subscriber_notification_title">Mendengarkan notifikasi masuk</string>
<string name="channel_subscriber_notification_title">Mendengarkan untuk notifikasi masuk</string>
<string name="channel_subscriber_notification_instant_text">Berlangganan ke topik pengiriman instan</string>
<string name="channel_subscriber_notification_instant_text_one">Berlangganan ke satu topik pengiriman instan</string>
<string name="channel_subscriber_notification_instant_text_two">Berlangganan ke dua topik pengiriman instan</string>
@ -19,11 +19,11 @@
\n%2$s</string>
<string name="refresh_message_error_one">Tidak dapat memuat ulang langganan: %1$s</string>
<string name="main_action_bar_title">Topik berlangganan</string>
<string name="main_menu_notifications_enabled">Notifikasi menyala</string>
<string name="main_menu_notifications_disabled_forever">Notifikasi dibisukan</string>
<string name="main_menu_notifications_disabled_until">Notifikasi dibisukan sampai %1$s</string>
<string name="main_menu_notifications_enabled">Notifikasi nyala</string>
<string name="main_menu_notifications_disabled_forever">Notifikasi dijeda</string>
<string name="main_menu_notifications_disabled_until">Notifikasi dijeda sampai %1$s</string>
<string name="main_menu_settings_title">Pengaturan</string>
<string name="main_menu_report_bug_title">Laporkan kutu</string>
<string name="main_menu_report_bug_title">Laporkan sebuah kutu</string>
<string name="main_menu_docs_title">Baca dokumentasi</string>
<string name="main_menu_rate_title">Beri nilai aplikasi ⭐</string>
<string name="main_action_mode_menu_unsubscribe">Batalkan langganan</string>
@ -35,12 +35,13 @@
<string name="main_how_to_intro">Tekan + untuk membuat atau berlangganan ke sebuah topik. Setelah itu Anda menerima notifikasi pada perangkat Anda saat mengirim pesan via PUT atau POST.</string>
<string name="main_how_to_link">Instruksi rinci tersedia di ntfy.sh, dan dalam dokumentasi.</string>
<string name="main_unified_push_toast">Langganan ini dikelola oleh %1$s melalui UnifiedPush</string>
<string name="main_banner_battery_text">Pengoptimalan baterai untuk aplikasi sebaiknya dimatikan supaya masalah pengiriman notifikasi dapat dihindari.</string>
<string name="main_banner_battery_text">Pengoptimalan baterai untuk aplikasi seharusnya mati supaya masalah pengiriman notifikasi dapat dihindari.</string>
<string name="main_banner_battery_button_remind_later">Tanya nanti</string>
<string name="main_banner_battery_button_dismiss">Abaikan</string>
<string name="main_banner_battery_button_fix_now">Perbaiki sekarang</string>
<string name="main_banner_websocket_button_remind_later">Tanya nanti</string>
<string name="main_banner_websocket_button_dismiss">Abaikan</string>
<string name="main_banner_json_stream_text">Ubah ke WebSockets dalam Pengaturan / \"Protokol koneksi\" sekarang untuk memastikan Anda dapat berkomunikasi dengan server ntfy Anda setelah Juni 2022.</string>
<string name="main_banner_json_stream_button_remind_later">Tanya nanti</string>
<string name="main_banner_json_stream_button_dismiss">Abaikan</string>
<string name="add_dialog_title">Berlangganan ke sebuah topik</string>
<string name="add_dialog_description_below">Topik mungkin tidak dilindungi oleh kata sandi, jadi pilih sebuah nama yang susah untuk ditebak. Setelah berlangganan, Anda dapat PUT/POST notifikasi.</string>
<string name="add_dialog_topic_name_hint">Nama topik, mis. pemberitahuan_andi</string>
@ -54,7 +55,7 @@
<string name="add_dialog_login_error_not_authorized">Login gagal. Pengguna %1$s tidak diizinkan.</string>
<string name="add_dialog_login_new_user">Pengguna baru</string>
<string name="detail_no_notifications_text">Anda belum menerima notifikasi apa pun.</string>
<string name="detail_how_to_intro">Untuk mengirimkan notifikasi ke topik ini, lakukan PUT atau POST ke URL topik.</string>
<string name="detail_how_to_intro">Untuk mengirimkan notifikasi ke topik ini, tinggal PUT atau POST ke URL topik.</string>
<string name="detail_how_to_example">Contoh (menggunakan curl):<br/><tt>$ curl -d \"Hai\" %1$s</tt></string>
<string name="detail_how_to_link">Instruksi rinci tersedia di ntfy.sh, dan dalam dokumentasi.</string>
<string name="detail_clear_dialog_message">Hapus semua notifikasi di topik ini\?</string>
@ -68,7 +69,7 @@
<string name="detail_test_message_error_unauthorized_anon">Tidak dapat mengirimkan pesan: Penerbitan anonim tidak diizinkan.</string>
<string name="detail_test_message_error_too_large">Tidak dapat mengirimkan pesan: Lampiran terlalu besar.</string>
<string name="detail_copied_to_clipboard_message">Disalin ke papan klip</string>
<string name="detail_instant_delivery_enabled">Pengiriman instan menyala</string>
<string name="detail_instant_delivery_enabled">Pengiriman instan nyala</string>
<string name="detail_instant_delivery_disabled">Pengiriman instan mati</string>
<string name="detail_item_tags">Tanda: %1$s</string>
<string name="detail_item_snack_deleted">Notifikasi dihapus</string>
@ -91,7 +92,7 @@
<string name="detail_item_download_info_deleted_expired">terhapus, tautan kadaluwarsa</string>
<string name="detail_item_download_info_download_failed">unduhan gagal</string>
<string name="detail_item_download_info_download_failed_expired">unduhan gagal, tautan kadaluwarsa</string>
<string name="detail_menu_notifications_disabled_until">Notifikasi dibisukan sampai %1$s</string>
<string name="detail_menu_notifications_disabled_until">Notifikasi dijeda sampai %1$s</string>
<string name="detail_menu_enable_instant">Aktifkan pengiriman instan</string>
<string name="detail_menu_disable_instant">Matikan pengiriman instan</string>
<string name="detail_menu_test">Kirim notifikasi uji coba</string>
@ -113,7 +114,7 @@
<string name="share_topic_title">Bagikan ke</string>
<string name="share_suggested_topics">Topik yang disarankan</string>
<string name="share_successful">Pesan dipublikasikan</string>
<string name="notification_dialog_title">Bisukan notifikasi</string>
<string name="notification_dialog_title">Jeda notifikasi</string>
<string name="notification_dialog_cancel">Batal</string>
<string name="notification_dialog_save">Simpan</string>
<string name="notification_dialog_show_all">Tampilkan semua notifikasi</string>
@ -122,10 +123,10 @@
<string name="notification_dialog_2h">2 jam</string>
<string name="settings_title">Pengaturan</string>
<string name="settings_notifications_header">Notifikasi</string>
<string name="settings_notifications_muted_until_title">Bisukan notifikasi</string>
<string name="settings_notifications_muted_until_title">Jeda notifikasi</string>
<string name="settings_notifications_muted_until_show_all">Menampilkan semua notifikasi</string>
<string name="settings_notifications_muted_until_forever">Notifikasi dibisukan sampai dilanjutkan</string>
<string name="settings_notifications_muted_until_x">Notifikasi dibisukan sampai %1$s</string>
<string name="settings_notifications_muted_until_forever">Notifikasi dijeda sampai dilanjutkan</string>
<string name="settings_notifications_muted_until_x">Notifikasi dijeda sampai %1$s</string>
<string name="settings_notifications_min_priority_title">Prioritas minimum</string>
<string name="settings_notifications_min_priority_summary_max">Tampilkan notifikasi jika prioritas adalah 5 (maks)</string>
<string name="settings_notifications_min_priority_min">Prioritas apa pun</string>
@ -165,8 +166,8 @@
<string name="settings_general_users_prefs_user_used_by_many">Digunakan oleh topik %1$s</string>
<string name="settings_general_users_prefs_user_add_title">Tambahkan pengguna baru</string>
<string name="settings_general_dark_mode_title">Mode gelap</string>
<string name="settings_general_dark_mode_summary_light">Mode terang menyala</string>
<string name="settings_general_dark_mode_summary_dark">Mode gelap menyala. Apakah Anda seorang vampir\?</string>
<string name="settings_general_dark_mode_summary_light">Mode terang nyala</string>
<string name="settings_general_dark_mode_summary_dark">Mode gelap nyala. Apakah Anda seorang vampir\?</string>
<string name="settings_general_dark_mode_entry_system">Gunakan bawaan sistem</string>
<string name="settings_general_dark_mode_entry_light">Mode terang</string>
<string name="settings_general_dark_mode_entry_dark">Mode gelap</string>
@ -198,8 +199,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 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_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_entry_jsonhttp">Aliran JSON melalui HTTP</string>
<string name="settings_advanced_connection_protocol_entry_ws">WebSockets</string>
<string name="settings_about_header">Tentang</string>
@ -210,18 +211,19 @@
<string name="user_dialog_base_url_hint">URL Layanan</string>
<string name="channel_subscriber_notification_noinstant_text_one">Berlangganan ke satu topik</string>
<string name="detail_item_menu_copy_contents_copied">Notifikasi disalin ke papan klip</string>
<string name="detail_item_cannot_open_url">Tidak dapat membuka URL: %1$s</string>
<string name="detail_item_cannot_open_click_url">Tidak dapat membuka URL: %1$s</string>
<string name="settings_notifications_min_priority_summary_any">Menampilkan semua notifikasi</string>
<string name="settings_notifications_min_priority_summary_x_or_higher">Tampilkan notifikasi jika prioritas adalah %1$d (%2$s) atau di atas</string>
<string name="settings_notifications_auto_download_summary_always">Unduh semua lampiran secara otomatis</string>
<string name="settings_notifications_auto_download_500k">Jika di bawah 500 kB</string>
<string name="user_dialog_button_save">Simpan</string>
<string name="channel_notifications_high_name">Prioritas tinggi</string>
<string name="channel_notifications_high_name">Notifikasi (prioritas tinggi)</string>
<string name="main_action_mode_delete_dialog_permanently_delete">Hapus secara permanen</string>
<string name="add_dialog_button_subscribe">Berlangganan</string>
<string name="channel_subscriber_notification_instant_text_more">Berlangganan ke %1$d topik pengiriman instan</string>
<string name="channel_subscriber_notification_noinstant_text_four">Berlangganan ke empat topik</string>
<string name="refresh_message_result">%1$d notifikasi diterima</string>
<string name="main_banner_json_stream_button_learn_more">Pelajari lebih lanjut</string>
<string name="channel_subscriber_notification_noinstant_text_three">Berlangganan ke tiga topik</string>
<string name="channel_subscriber_notification_noinstant_text_more">Berlangganan ke %1$d topik</string>
<string name="add_dialog_instant_delivery_description">Memastikan pesan dikirim dengan segera, bahkan jika perangkatnya tidak aktif.</string>
@ -236,7 +238,7 @@
<string name="main_item_status_text_not_one">%1$d notifikasi</string>
<string name="detail_test_message">Ini adalah notifikasi uji coba dari aplikasi Android ntfy. Ini memiliki tingkat prioritas %1$d. Jika Anda kirim yang lain, itu mungkin kelihatan berbeda.</string>
<string name="detail_test_message_error_unauthorized_user">Tidak dapat mengirimkan pesan: Pengguna \"%1$s\" tidak diizinkan.</string>
<string name="detail_menu_notifications_enabled">Notifikasi menyala</string>
<string name="detail_menu_notifications_enabled">Notifikasi nyala</string>
<string name="notification_popup_file_download_successful">%1$s
\nFile: %2$s, terunduh</string>
<string name="detail_item_saved_successfully">Disimpan sebagai \"%1$s\" dalam folder \"Downloads\"</string>
@ -248,14 +250,14 @@
<string name="share_menu_send">Bagikan</string>
<string name="detail_item_download_failed">Tidak dapat mengunduh lampiran: %1$s</string>
<string name="share_content_text_hint">Tambahkan konten di sini untuk dibagikan</string>
<string name="notification_dialog_muted_forever_toast_message">Notifikasi dibisukan</string>
<string name="notification_dialog_muted_forever_toast_message">Notifikasi dijeda</string>
<string name="notification_dialog_8h">8 jam</string>
<string name="notification_dialog_forever">Sampai dilanjutkan</string>
<string name="notification_popup_action_open">Buka</string>
<string name="settings_notifications_min_priority_default">Prioritas default dan di atas</string>
<string name="settings_notifications_priority_high">tinggi</string>
<string name="settings_notifications_auto_download_1m">Jika di bawah 1 MB</string>
<string name="settings_advanced_record_logs_summary_disabled">Nyalakan pencatatan, supaya Anda dapat membagikan catatan nanti untuk mendiagnosa masalah.</string>
<string name="settings_advanced_record_logs_summary_disabled">Nyalakan pencatatan supaya Anda dapat membagikan catatan nanti untuk mendiagnosa masalah.</string>
<string name="settings_advanced_export_logs_error_uploading">Tidak dapat mengunggah catatan: %1$s</string>
<string name="settings_advanced_export_logs_scrub_dialog_text">Topik/nama host diganti dengan nama-nama buah, jadi Anda dapat membagikan catatan tanpa khawatir:
\n
@ -263,7 +265,7 @@
\n
\nKata sandi dihilangkan, tetapi tidak didaftarkan di sini.</string>
<string name="detail_item_download_info_deleted_expires_x">terhapus, tautan kadaluwarsa %1$s</string>
<string name="detail_menu_notifications_disabled_forever">Notifikasi dibisukan</string>
<string name="detail_menu_notifications_disabled_forever">Notifikasi dijeda</string>
<string name="notification_dialog_enabled_toast_message">Notifikasi dilanjutkan</string>
<string name="notification_dialog_tomorrow">Sampai besok</string>
<string name="notification_popup_action_browse">Telusuri</string>
@ -275,7 +277,7 @@
\n%3$s</string>
<string name="settings_notifications_min_priority_low">Prioritas rendah dan di atas</string>
<string name="settings_notifications_priority_max">maks</string>
<string name="notification_dialog_muted_until_toast_message">Notifikasi dibisukan sampai %1$s</string>
<string name="notification_dialog_muted_until_toast_message">Notifikasi dijeda sampai %1$s</string>
<string name="notification_popup_file_download_failed">%1$s
\nFile: %2$s, unduhan gagal</string>
<string name="user_dialog_title_add">Tambahkan pengguna</string>
@ -289,7 +291,7 @@
<string name="settings_backup_restore_restore_failed">Pemulihan gagal: %1$s</string>
<string name="settings_advanced_header">Tingkat lanjut</string>
<string name="settings_advanced_broadcast_summary_enabled">Aplikasi dapat menerima notifikasi yang datang sebagai siaran</string>
<string name="settings_advanced_export_logs_summary">Salin catatan ke papan klip, atau unggah ke nopaste.net (dimiliki oleh penulis ntfy). Nama host dan topik dapat disensor, notifikasi tidak akan disensor.</string>
<string name="settings_advanced_export_logs_summary">Salin catatan ke papn klip, atau unggah ke nopaste.net (dimiliki oleh penulis ntfy). Nama host dan topik dapat disensor, notifikasi tidak akan disensor.</string>
<string name="settings_about_version_copied_to_clipboard_message">Disalin ke papan klip</string>
<string name="user_dialog_password_hint_add">Kata Sandi</string>
<string name="user_dialog_button_delete">Hapus pengguna</string>
@ -299,48 +301,4 @@
<string name="user_dialog_button_add">Tambahkan pengguna</string>
<string name="user_dialog_button_cancel">Batal</string>
<string name="detail_deep_link_subscribed_toast_message">Berlangganan ke topik %1$s</string>
<string name="settings_notifications_channel_prefs_summary">Timpaan Jangan Ganggu (DND), suara, dll.</string>
<string name="settings_notifications_channel_prefs_title">Pengaturan saluran</string>
<string name="notification_popup_user_action_failed">%1$s gagal: %2$s</string>
<string name="channel_subscriber_notification_instant_text_five">Berlangganan ke lima topik pengiriman instan</string>
<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. 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>
<string name="detail_settings_appearance_icon_remove_summary">Ikon ditampilkan di notifikasi untuk topik ini</string>
<string name="detail_settings_appearance_icon_error_saving">Tidak dapat menyimpan ikon: %1$s</string>
<string name="detail_settings_global_setting_title">Gunakan pengaturan global</string>
<string name="detail_settings_global_setting_suffix">menggunakan pengaturan global</string>
<string name="detail_settings_notifications_instant_title">Pengiriman instan</string>
<string name="detail_settings_notifications_instant_summary_off">Notifikasi dikirim menggunakan Firebase. Pengiriman mungkin telat, tetapi mengkonsumsi lebih sedikit baterai.</string>
<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>
<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>
<string name="detail_settings_appearance_display_name_title">Nama tampilan</string>
<string name="detail_settings_appearance_display_name_default_summary">%1$s (bawaan)</string>
<string name="detail_settings_appearance_display_name_message">Tetapkan sebuah nama tampilan kustom untuk langganan ini. Tinggalkan kosong untuk bawaan (%1$s).</string>
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">Disalin ke papan klip</string>
<string name="detail_settings_about_header">Tentang</string>
<string name="detail_settings_about_topic_url_title">URL Topik</string>
<string name="main_menu_donate_title">Donasi 💸</string>
<string name="detail_item_cannot_open_apk">Aplikasi tidak dapat dipasang lagi. Unduh melalui peramban. Lihat masalah #531 untuk detail lebih lanjut.</string>
<string name="settings_notifications_insistent_max_priority_summary_disabled">Notifikasi prioritas maks hanya memperingati sekali</string>
<string name="detail_settings_notifications_open_channels_title">Atur pengaturan notifikasi</string>
<string name="detail_settings_notifications_open_channels_summary">Sampingan Jangan Ganggu, suara, dll.</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_disabled">Peringati hanya sekali</string>
<string name="channel_notifications_group_default_name">Bawaan</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_enabled">Tetap memperingati</string>
<string name="settings_notifications_insistent_max_priority_title">Tetap memperingati untuk prioritas tertinggi</string>
<string name="settings_notifications_insistent_max_priority_summary_enabled">Notifikasi prioritas maks memperingatkan secara berkelanjutan sampai diabaikan</string>
<string name="detail_settings_notifications_dedicated_channels_title">Pengaturan notifikasi kustom</string>
<string name="detail_settings_notifications_dedicated_channels_summary_on">Menggunakan pengaturan kustom untuk langganan ini</string>
<string name="detail_settings_notifications_dedicated_channels_summary_off">Menggunakan pengaturan bawaan (suara, sampingan Jangan Ganggu, dll.)</string>
<string name="settings_advanced_unifiedpush_summary_enabled">ntfy akan menjadi sebagai distributor UnifiedPush</string>
<string name="settings_advanced_unifiedpush_summary_disabled">ntfy tidak akan menjadi sebagai distributor UnifiedPush</string>
<string name="settings_advanced_unifiedpush_title">Aktifkan UnifiedPush</string>
</resources>

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="channel_notifications_low_name">Priorità bassa</string>
<string name="channel_notifications_low_name">Notifiche (priorità bassa)</string>
<string name="channel_subscriber_notification_noinstant_text_three">Iscritto a tre topic</string>
<string name="channel_notifications_high_name">Priorità alta</string>
<string name="channel_notifications_max_name">Priorità massima</string>
<string name="channel_notifications_high_name">Notifiche (priorità alta)</string>
<string name="channel_notifications_max_name">Notifiche (priorità massima)</string>
<string name="channel_subscriber_service_name">Servizio di iscrizione</string>
<string name="channel_subscriber_notification_instant_text">Iscritto ai topic a consegna istantanea</string>
<string name="channel_subscriber_notification_instant_text_two">Iscritto a due topic a consegna istantanea</string>
@ -20,8 +20,8 @@
\n%2$s</string>
<string name="refresh_message_error_one">Impossibile aggiornare l\'iscrizione: %1$s</string>
<string name="main_menu_notifications_enabled">Notifiche ON</string>
<string name="main_menu_notifications_disabled_forever">Notifiche disattivate</string>
<string name="main_menu_notifications_disabled_until">Notiche disattivate fino a %1$s</string>
<string name="main_menu_notifications_disabled_forever">Notifiche in pausa</string>
<string name="main_menu_notifications_disabled_until">Notiche in pausa fino a %1$s</string>
<string name="main_menu_settings_title">Impostazioni</string>
<string name="main_action_bar_title">Topic iscritti</string>
<string name="main_action_mode_delete_dialog_message">Disiscriversi dai topic selezionati ed eliminare definitivamente tutte le notifiche\?</string>
@ -36,12 +36,13 @@
<string name="main_banner_battery_button_remind_later">Chiedi in seguito</string>
<string name="main_banner_battery_button_dismiss">Abbandona</string>
<string name="main_banner_battery_button_fix_now">Correggi ora</string>
<string name="main_banner_websocket_button_remind_later">Chiedi in seguito</string>
<string name="main_banner_websocket_button_dismiss">Abbandona</string>
<string name="main_banner_json_stream_text">Passa ora a WebSockets in Impostazioni/\"Protocollo di connessione\" per poter comunicare con il tuo server ntfy selfhosted dopo giugno 2022.</string>
<string name="main_banner_json_stream_button_remind_later">Chiedi in seguito</string>
<string name="main_banner_json_stream_button_dismiss">Abbandona</string>
<string name="add_dialog_title">Iscriviti al topic</string>
<string name="add_dialog_topic_name_hint">Nome del topic, es. phils_alerts</string>
<string name="add_dialog_use_another_server">Usa un altro server</string>
<string name="add_dialog_use_another_server_description">Immettere gli URL dei servizi qui sotto per iscriversi ai topic di altri server.</string>
<string name="add_dialog_use_another_server_description">Inserisci qui sotto l\'URL del server per iscriverti ai topic da altri server.</string>
<string name="add_dialog_instant_delivery">Consegna istantanea in modalità doze</string>
<string name="add_dialog_foreground_description">La consegna istantanea è sempre attiva per gli host diversi da %1$s.</string>
<string name="add_dialog_button_cancel">Cancella</string>
@ -72,7 +73,7 @@
<string name="detail_item_menu_copy_contents_copied">Notifica copiata negli appunti</string>
<string name="detail_item_cannot_download">Impossibile aprire o scaricare l\'allegato. Il link è scaduto e nessun file locale è stato trovato.</string>
<string name="detail_item_cannot_open">Impossibile aprire l\'allegato: %1$s</string>
<string name="detail_item_cannot_open_url">Impossibile aprire URL: %1$s</string>
<string name="detail_item_cannot_open_click_url">Impossibile aprire URL: %1$s</string>
<string name="detail_item_cannot_delete">Impossibile eliminare l\'allegato: %1$s</string>
<string name="detail_item_download_failed">Impossibile scaricare l\'allegato: %1$s</string>
<string name="detail_item_download_info_not_downloaded">non scaricato</string>
@ -84,8 +85,8 @@
<string name="detail_item_download_info_deleted_expires_x">eliminato, scadenza link %1$s</string>
<string name="detail_item_download_info_download_failed">download fallito</string>
<string name="detail_item_download_info_download_failed_expired">download fallito, link scaduto</string>
<string name="detail_menu_notifications_disabled_forever">Notifiche disattivate</string>
<string name="detail_menu_notifications_disabled_until">Notifiche disattivate fino a %1$s</string>
<string name="detail_menu_notifications_disabled_forever">Notifiche in pausa</string>
<string name="detail_menu_notifications_disabled_until">Notifiche in pausa fino a %1$s</string>
<string name="detail_menu_enable_instant">Abilita consegna istantanea</string>
<string name="detail_menu_disable_instant">Disabilita consegna istantanea</string>
<string name="detail_menu_test">Invia notifica di test</string>
@ -118,9 +119,9 @@
<string name="notification_popup_file_download_failed">%1$s
\nFile: %2$s, download fallito</string>
<string name="settings_title">Impostazioni</string>
<string name="settings_notifications_muted_until_title">Disattiva le notifiche</string>
<string name="settings_notifications_muted_until_title">Metti in pausa le notifiche</string>
<string name="settings_notifications_muted_until_show_all">Mostra tutte le notifiche</string>
<string name="settings_notifications_muted_until_x">Notifiche disattivate fino a %1$s</string>
<string name="settings_notifications_muted_until_x">Notifiche in pausa fino a %1$s</string>
<string name="settings_notifications_min_priority_title">Priorità minima</string>
<string name="settings_notifications_min_priority_summary_any">Mostra tutte le notifiche</string>
<string name="settings_notifications_min_priority_summary_x_or_higher">Mostra notifiche se la priorità è %1$d (%2$s) o superiore</string>
@ -166,11 +167,11 @@
\nLe password sono state ripulite, ma non sono elencate qui.</string>
<string name="settings_advanced_export_logs_scrub_dialog_button_ok">Ok</string>
<string name="settings_advanced_clear_logs_title">Cancella i log</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Usa stream JSON over HTTP per collegarti al server. Questo metodo è collaudato, ma può consumare più batteria.</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Usa stream JSON over HTTP per collegarti al server. Questo metodo è deprecato e sarà rimosso a giugno 2022.</string>
<string name="settings_advanced_connection_protocol_entry_jsonhttp">Stream JSON over HTTP</string>
<string name="user_dialog_description_add">Puoi aggiungere un utente qui. Tutti i topic per il dato server utilizzeranno questo utente.</string>
<string name="user_dialog_description_edit">Puoi modificare username/password per l\'utente selezionato, oppure eliminarlo.</string>
<string name="user_dialog_base_url_hint">URL del servizio</string>
<string name="user_dialog_base_url_hint">Server URL</string>
<string name="user_dialog_username_hint">Username</string>
<string name="user_dialog_password_hint_add">Password</string>
<string name="user_dialog_password_hint_edit">Password (non modificata se il campo viene lasciato vuoto)</string>
@ -179,8 +180,8 @@
<string name="user_dialog_button_delete">Elimina utente</string>
<string name="user_dialog_button_save">Salva</string>
<string name="channel_subscriber_notification_noinstant_text_more">Iscritto a %1$d topic</string>
<string name="channel_notifications_default_name">Priorità di default</string>
<string name="channel_notifications_min_name">Priorità minima</string>
<string name="channel_notifications_default_name">Notifiche (priorità di default)</string>
<string name="channel_notifications_min_name">Notifiche (priorità minima)</string>
<string name="channel_subscriber_notification_instant_text_one">Iscritto a un topic a consegna istantanea</string>
<string name="channel_subscriber_notification_noinstant_text_four">Iscritto a quattro topic</string>
<string name="main_menu_docs_title">Leggi la documentazione</string>
@ -192,6 +193,7 @@
<string name="main_no_subscriptions_text">Sembra che non ci sia nessuna iscrizione al momento.</string>
<string name="main_menu_report_bug_title">Segnala un bug</string>
<string name="main_menu_rate_title">Valuta l\'app ⭐</string>
<string name="main_banner_json_stream_button_learn_more">Scopri di più</string>
<string name="add_dialog_description_below">I topic possono essere non protetti da password, per cui scegli un nome che è difficile da indovinare. Una volta iscritti, è possibile effettuare notifiche PUT/POST.</string>
<string name="add_dialog_instant_delivery_description">Assicura che i messaggi siano consegnati immediatamente, anche se il device non è attivo.</string>
<string name="add_dialog_login_description">Questo topic richiede il login. Per favore, inserire username e password.</string>
@ -241,15 +243,15 @@
<string name="settings_notifications_header">Notifiche</string>
<string name="share_content_file_error">Impossibile leggere le informazioni del file: %1$s</string>
<string name="notification_popup_action_open">Apri</string>
<string name="settings_notifications_muted_until_forever">Notifiche disattivate fino al ripristino</string>
<string name="settings_notifications_muted_until_forever">Notiche in pausa fino al ripristino</string>
<string name="settings_notifications_auto_download_5m">Se sotto 5 MB</string>
<string name="share_content_file_text">Un file è stato condiviso con te</string>
<string name="share_suggested_topics">Topic suggeriti</string>
<string name="notification_dialog_title">Disattivare le notifiche</string>
<string name="notification_dialog_title">Metti in pausa le notifiche</string>
<string name="notification_dialog_save">Salva</string>
<string name="notification_dialog_enabled_toast_message">Notifiche ripristinate</string>
<string name="notification_dialog_muted_forever_toast_message">Notifiche disattivate</string>
<string name="notification_dialog_muted_until_toast_message">Notifiche disattivate fino a %1$s</string>
<string name="notification_dialog_muted_forever_toast_message">Notifiche in pausa</string>
<string name="notification_dialog_muted_until_toast_message">Notifiche in pausa fino a %1$s</string>
<string name="notification_dialog_30min">30 minuti</string>
<string name="notification_dialog_2h">2 ore</string>
<string name="notification_dialog_8h">8 ore</string>
@ -285,7 +287,7 @@
<string name="settings_advanced_export_logs_uploading">Log in upload …</string>
<string name="settings_advanced_clear_logs_summary">Elimina i log precedentemente salvati, e ricomincia</string>
<string name="settings_advanced_connection_protocol_title">Protocollo di connessione</string>
<string name="settings_advanced_connection_protocol_summary_ws">Usa WebSockets per collegarti al server. Questo è il metodo consigliato, ma potrebbe richiedere una configurazione aggiuntiva del proxy.</string>
<string name="settings_advanced_connection_protocol_summary_ws">Usa WebSockets per collegarti al server. Questo metodo diventerà il default a giugno 2022.</string>
<string name="settings_advanced_connection_protocol_entry_ws">WebSockets</string>
<string name="user_dialog_title_add">Aggiungi utente</string>
<string name="settings_about_version_copied_to_clipboard_message">Copiato negli appunti</string>
@ -298,38 +300,4 @@
<string name="settings_notifications_priority_high">alta</string>
<string name="settings_notifications_priority_min">minima</string>
<string name="settings_notifications_priority_low">bassa</string>
<string name="detail_deep_link_subscribed_toast_message">Iscritto al topic %1$s</string>
<string name="detail_settings_global_setting_title">Utilizzare l\'impostazione globale</string>
<string name="settings_notifications_channel_prefs_summary">Esclusione del DND (Do Not Disturb), suoni, ecc.</string>
<string name="channel_subscriber_notification_instant_text_five">Iscritto a cinque topic a consegna istantanea</string>
<string name="channel_subscriber_notification_instant_text_six">Iscritto a sei topic a consegna istantanea</string>
<string name="channel_subscriber_notification_noinstant_text_five">Iscritto a cinque topic</string>
<string name="channel_subscriber_notification_noinstant_text_six">Iscritto a sei topic</string>
<string name="notification_popup_user_action_failed">%1$s fallito: %2$s</string>
<string name="settings_notifications_channel_prefs_title">Impostazioni del canale</string>
<string name="detail_settings_notifications_instant_title">Consegna istantanea</string>
<string name="detail_settings_notifications_instant_summary_on">Le notifiche vengono consegnate istantaneamente. Richiede un servizio in primo piano e consuma più batteria.</string>
<string name="detail_settings_notifications_instant_summary_off">Le notifiche vengono inviate utilizzando Firebase. La consegna può essere ritardata, ma consuma meno batteria.</string>
<string name="detail_settings_appearance_header">Aspetto</string>
<string name="detail_settings_appearance_icon_set_title">Icona della sottoscrizione</string>
<string name="detail_settings_appearance_icon_set_summary">Impostare un\'icona da visualizzare nelle notifiche</string>
<string name="detail_settings_appearance_icon_remove_title">Icona della sottoscrizione (toccare per rimuovere)</string>
<string name="detail_settings_appearance_icon_remove_summary">Icona visualizzata nelle notifiche di questo topic</string>
<string name="detail_settings_appearance_icon_error_saving">Impossibile salvare l\'icona: %1$s</string>
<string name="detail_settings_global_setting_suffix">utilizzando l\'impostazione globale</string>
<string name="detail_settings_appearance_display_name_title">Nome visualizzato</string>
<string name="main_banner_websocket_text">E\' consigliato il passaggio a WebSockets per connettersi al server e potrebbe migliorare la durata della batteria, ma potrebbe richiedere <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">un\'ulteriore configurazione del proxy</a>. Questa opzione può essere selezionata nelle Impostazioni.</string>
<string name="detail_settings_appearance_display_name_default_summary">%1$s (predefinito)</string>
<string name="detail_settings_appearance_display_name_message">Impostare un nome di visualizzazione personalizzato per questa iscrizione. Lasciare vuoto per il nome predefinito (%1$s).</string>
<string name="detail_settings_about_header">Informazioni</string>
<string name="detail_settings_about_topic_url_title">URL argomento</string>
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">Copiato negli appunti</string>
<string name="add_dialog_base_urls_dropdown_choose">Scegli il servizio URL</string>
<string name="add_dialog_base_urls_dropdown_clear">Pulisci il servizio URL</string>
<string name="main_banner_websocket_button_enable_now">Attiva ora</string>
<string name="channel_notifications_group_default_name">Default</string>
<string name="main_menu_donate_title">Dona 💸</string>
<string name="detail_item_cannot_open_apk">Le app non possono più essere installate: devono essere scaricate via browser. Vedi l\'issue #531 per dettagli.</string>
<string name="eos_settings_enable_title">Abilitare il distributore</string>
<string name="eos_settings_enable_description">Consente alle applicazioni di terze parti di ricevere notifiche UnifiedPush</string>
</resources>

View file

@ -1,315 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="channel_subscriber_notification_noinstant_text_more">מנוי ל־%1$d נושאים</string>
<string name="refresh_message_result">%1$d התראות התקבלו</string>
<string name="refresh_message_no_results">הכול עדכני</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_until">ההתראות מושתקות עד %1$s</string>
<string name="main_menu_settings_title">הגדרות</string>
<string name="main_menu_report_bug_title">דיווח על תקלה</string>
<string name="main_menu_docs_title">הצגת התיעוד</string>
<string name="main_menu_rate_title">דירוג היישומון ⭐</string>
<string name="main_action_mode_menu_unsubscribe">ביטול מינוי</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_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="channel_notifications_min_name">עדיפות מזערית</string>
<string name="channel_subscriber_service_name">שירות מנויים</string>
<string name="channel_subscriber_notification_title">בהאזנה להתראות נכנסות</string>
<string name="channel_notifications_low_name">עדיפות נמוכה</string>
<string name="channel_notifications_default_name">עדיפות ברירת מחדל</string>
<string name="channel_notifications_high_name">עדיפות גבוהה</string>
<string name="channel_notifications_max_name">עדיפות מרבית</string>
<string name="refresh_message_error">הרענון של %1$d מהרישומים נכשל
\n
\n%2$s</string>
<string name="main_menu_notifications_disabled_forever">התראות מושתקות</string>
<string name="main_action_mode_delete_dialog_message">לבטל מינוי מהנושאים שנבחרו ולמחוק את כל ההתראות לצמיתות?</string>
<string name="main_item_status_reconnecting">התחברות מחדש…</string>
<string name="main_how_to_intro">לחיצה על + תאפשר ליצור או להירשם לנושא. לאחר מכן התראות תגענה למכשיר שלך בעת שליחת הודעות עם PUT או POST.</string>
<string name="main_how_to_link">הוראות מפורטות זמינות ב־ntfy.sh, ובתיעוד.</string>
<string name="main_menu_donate_title">תרומה 💸</string>
<string name="channel_subscriber_notification_instant_text_two">מנוי לשני נושאים במשלוח מהיר</string>
<string name="channel_subscriber_notification_instant_text_three">מנוי לשלושה נושאים במשלוח מהיר</string>
<string name="channel_subscriber_notification_instant_text">מנוי לנושאים במשלוח מהיר</string>
<string name="channel_subscriber_notification_instant_text_one">מנוי לנושא אחד במשלוח מהיר</string>
<string name="channel_subscriber_notification_instant_text_four">מנוי לארבעה נושאים במשלוח מהיר</string>
<string name="channel_subscriber_notification_instant_text_five">מנוי לחמישה נושאים במשלוח מהיר</string>
<string name="channel_subscriber_notification_instant_text_six">מנוי לשישה נושאים במשלוח מהיר</string>
<string name="channel_subscriber_notification_instant_text_more">מנוי ל־%1$d נושאים במשלוח מהיר</string>
<string name="channel_subscriber_notification_noinstant_text">מנוי לנושאים</string>
<string name="channel_subscriber_notification_noinstant_text_one">מנוי לנושא אחד</string>
<string name="channel_subscriber_notification_noinstant_text_two">מנוי לשני נושאים</string>
<string name="channel_subscriber_notification_noinstant_text_three">מנוי לשלושה נושאים</string>
<string name="channel_subscriber_notification_noinstant_text_four">מנוי לארבעה נושאים</string>
<string name="channel_subscriber_notification_noinstant_text_five">מנוי לחמישה נושאים</string>
<string name="channel_subscriber_notification_noinstant_text_six">מנוי לשישה נושאים</string>
<string name="channel_notifications_group_default_name">ברירת מחדל</string>
<string name="add_dialog_description_below">כנראה שהנושאים אינם מוגנים בסיסמה, אז כדאי לבחור שם שקשה לנחש. לאחר הרשמה, אפשר לשלוח התראות עם PUT/POST.</string>
<string name="main_banner_websocket_button_enable_now">להפעיל כעת</string>
<string name="add_dialog_topic_name_hint">שם הנושא, למשל: shimons_alerts</string>
<string name="add_dialog_use_another_server">להשתמש בשרת אחר</string>
<string name="add_dialog_instant_delivery">משלוח מיידי במצב תנומה</string>
<string name="main_banner_websocket_button_dismiss">התעלמות</string>
<string name="add_dialog_title">הרשמה לנושא</string>
<string name="main_item_status_unified_push">%1$s (UnifiedPush)</string>
<string name="detail_how_to_intro">כדי לשלוח התראות לנושא הזה צריך פשוט לשלוח בקשות PUT או POST לכתובת הנושא.</string>
<string name="detail_test_message_error_unauthorized_user">אי אפשר לשלוח הודעה: למשתמש „%1$s” אין הרשאה.</string>
<string name="detail_deep_link_subscribed_toast_message">נרשמת לנושא %1$s</string>
<string name="detail_item_tags">תגיות: %1$s</string>
<string name="detail_item_snack_undo">הסגה</string>
<string name="detail_item_menu_delete">מחיקת קובץ</string>
<string name="detail_menu_settings">הגדרות המינוי</string>
<string name="detail_action_mode_menu_delete">מחיקה</string>
<string name="notification_dialog_cancel">ביטול</string>
<string name="notification_dialog_muted_until_toast_message">ההתראות מושתקות עד %1$s</string>
<string name="notification_dialog_show_all">הצגת כל ההתראות</string>
<string name="notification_popup_user_action_failed">%1$s נכשל: %2$s</string>
<string name="settings_notifications_min_priority_summary_any">כל ההתראות מוצגות</string>
<string name="settings_notifications_min_priority_summary_max">להציג התראות אם העדיפות היא 5 (מרבית)</string>
<string name="settings_notifications_min_priority_min">כל עדיפות שהיא</string>
<string name="settings_notifications_min_priority_default">עדיפות ברירת מחדל ומעלה</string>
<string name="settings_notifications_min_priority_high">עדיפות גבוהה ומעלה</string>
<string name="settings_notifications_min_priority_max">עדיפות מרבית בלבד</string>
<string name="settings_notifications_priority_min">מזערית</string>
<string name="settings_notifications_auto_download_100k">אם מתחת ל־100 ק״ב</string>
<string name="settings_notifications_auto_download_500k">אם מתחת ל־500 ק״ב</string>
<string name="settings_notifications_auto_download_1m">אם מתחת ל־1 מ״ב</string>
<string name="settings_notifications_auto_download_5m">אם מתחת ל־5 מ״ב</string>
<string name="settings_notifications_auto_download_10m">אם מתחת ל־10 מ״ב</string>
<string name="settings_notifications_auto_download_50m">אם מתחת ל־50 מ״ב</string>
<string name="detail_item_download_info_downloading_x_percent">%1$d%% ירדו</string>
<string name="detail_menu_clear">פינוי כל ההתראות</string>
<string name="notification_popup_file_download_successful">%1$s
\nקובץ: %2$s, ירד</string>
<string name="notification_popup_file_download_failed">%1$s
\nקובץ: %2$s, ההורדה נכשלה</string>
<string name="settings_notifications_auto_delete_summary_never">לעולם לא למחוק התראות אוטומטית</string>
<string name="settings_general_users_title">ניהול משתמשים</string>
<string name="settings_general_users_summary">הוספת/הסרת משתמשים מ/על נושאים מוגנים</string>
<string name="settings_backup_restore_header">גיבוי ושחזור</string>
<string name="settings_backup_restore_backup_title">גיבוי לקובץ</string>
<string name="settings_backup_restore_backup_successful">נוצר גיבוי</string>
<string name="settings_advanced_broadcast_title">הודעות שידור</string>
<string name="settings_advanced_broadcast_summary_enabled">יישומונים יכולים לקבל התראות נכנסות בתור שידורים</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_enabled">להמשיך להודיע</string>
<string name="add_dialog_login_password_hint">סיסמה</string>
<string name="add_dialog_login_description">הנושא הזה דורש כניסה למערכת. נא למלא שם משתמש וסיסמה.</string>
<string name="add_dialog_login_error_not_authorized">הכניסה נכשלה. למשתמש %1$s אין הרשאה.</string>
<string name="add_dialog_login_new_user">משתמש חדש</string>
<string name="add_dialog_base_urls_dropdown_choose">נא לבחור כתובת שירות</string>
<string name="add_dialog_base_urls_dropdown_clear">מחיקת כתובת השירות</string>
<string name="detail_no_notifications_text">עדיין לא קיבלת התראות לנושא הזה.</string>
<string name="detail_how_to_example">דוגמה (עם curl):<br/><tt>$ curl -d \"Shalom\" %1$s</tt></string>
<string name="detail_how_to_link">יש הנחיות מפורטות ב־ntfy.sh ובתיעוד.</string>
<string name="detail_clear_dialog_message">למחוק את כל ההתראות בנושא הזה?</string>
<string name="detail_clear_dialog_permanently_delete">למחוק לצמיתות</string>
<string name="detail_clear_dialog_cancel">ביטול</string>
<string name="detail_delete_dialog_message">לבטל את המינוי לנושא הזה ולמחוק את כל ההתראות שהתקבלו?</string>
<string name="detail_test_message_error_too_large">אי אפשר לשלוח הודעה: הצרופה גדולה מדי.</string>
<string name="detail_item_menu_cancel">ביטול הורדה</string>
<string name="detail_item_menu_save_file">שמירת קובץ</string>
<string name="detail_item_menu_copy_contents_copied">ההתראה הועתקה ללוח הגזירים</string>
<string name="detail_item_cannot_download">אי אפשר לפתוח או להוריד את הצרופה. תוקף הקישור פג ואין קובץ מקומי.</string>
<string name="detail_item_cannot_save">לא ניתן לשמור צרופה: %1$s</string>
<string name="detail_item_download_info_not_downloaded">לא ירדה</string>
<string name="detail_item_download_info_deleted">נמחקה</string>
<string name="detail_item_download_info_deleted_expired">נמחקה, תוקף הקישור פג</string>
<string name="detail_item_download_info_download_failed_expires_x">ההורדה נכשלה, תוקף הקישור יפוג ב־%1$s</string>
<string name="detail_menu_notifications_disabled_forever">התראות מושתקות</string>
<string name="detail_menu_notifications_disabled_until">ההתראות מושתקות עד %1$s</string>
<string name="detail_menu_test">שליחת התראת בדיקה</string>
<string name="detail_menu_copy_url">העתקת כתובת הנושא</string>
<string name="detail_action_mode_menu_copy">העתקה</string>
<string name="share_title">שיתוף</string>
<string name="share_menu_send">שיתוף</string>
<string name="share_content_text_hint">הוספת הקשר לשיתוף כאן</string>
<string name="share_topic_title">שיתוף אל</string>
<string name="share_suggested_topics">נושאים מוצעים</string>
<string name="notification_dialog_title">השתקת התראות</string>
<string name="notification_dialog_save">שמירה</string>
<string name="notification_dialog_enabled_toast_message">ההתראות נמשכות</string>
<string name="notification_dialog_muted_forever_toast_message">ההתראות מושתקות</string>
<string name="notification_dialog_30min">חצי שעה</string>
<string name="notification_dialog_1h">שעה</string>
<string name="notification_dialog_2h">שעתיים</string>
<string name="notification_dialog_8h">8 שעות</string>
<string name="notification_dialog_tomorrow">עד מחר</string>
<string name="notification_popup_action_open">פתיחה</string>
<string name="notification_popup_action_browse">עיון</string>
<string name="notification_popup_action_download">הורדה</string>
<string name="notification_popup_action_cancel">ביטול</string>
<string name="notification_popup_file">%1$s
\nקובץ: %2$s</string>
<string name="settings_title">הגדרות</string>
<string name="settings_notifications_header">התראות</string>
<string name="settings_notifications_muted_until_show_all">כל ההתראות מוצגות</string>
<string name="settings_notifications_muted_until_forever">ההתראות מושתקות עד לביטול השתקה</string>
<string name="settings_notifications_muted_until_x">התראות מושתקות עד %1$s</string>
<string name="settings_notifications_min_priority_title">התראה מזערית</string>
<string name="settings_notifications_auto_delete_one_month">לאחר חודש</string>
<string name="settings_notifications_auto_delete_three_months">לאחר 3 חודשים</string>
<string name="settings_general_header">כללי</string>
<string name="settings_general_default_base_url_title">שרת ברירת מחדל</string>
<string name="settings_general_default_base_url_default_summary">%1$s (ברירת מחדל)</string>
<string name="settings_general_users_prefs_title">משתמשים</string>
<string name="settings_general_users_prefs_user_used_by_many">בשימוש הנושאים %1$s</string>
<string name="settings_general_users_prefs_user_add">הוספת משתמשים</string>
<string name="settings_general_users_prefs_user_add_title">הוספת משתמש חדש</string>
<string name="settings_general_users_prefs_user_add_summary">יצירת משתמש חדש לשרת חדש</string>
<string name="settings_general_dark_mode_title">מצב כהה</string>
<string name="settings_general_dark_mode_summary_system">ברירת מחדל המערכת</string>
<string name="settings_general_dark_mode_summary_light">מצב בהיר פעיל</string>
<string name="settings_general_dark_mode_summary_dark">מצב ככה פעיל. מדובר בערפד/ית?</string>
<string name="settings_backup_restore_backup_summary">ייצוא הגדרות, התראות ומשתמשים</string>
<string name="settings_backup_restore_backup_entry_everything">הכול</string>
<string name="settings_backup_restore_backup_entry_everything_no_users">הכול חוץ מהמשתמשים</string>
<string name="settings_backup_restore_backup_failed">הגיבוי נכשל: %1$s</string>
<string name="settings_backup_restore_restore_title">שחזור מקובץ</string>
<string name="settings_backup_restore_restore_failed">השחזור נכשל: %1$s</string>
<string name="settings_advanced_header">מתקדם</string>
<string name="settings_advanced_export_logs_copied_url">היומנים הועלו והכתובת הועתקה</string>
<string name="settings_advanced_export_logs_scrub_dialog_button_ok">אישור</string>
<string name="settings_advanced_export_logs_error_uploading">לא ניתן להעלות יומנים: %1$s</string>
<string name="settings_advanced_clear_logs_title">פינוי יומנים</string>
<string name="detail_settings_appearance_header">מראה</string>
<string name="detail_settings_appearance_icon_set_title">סמל מינוי</string>
<string name="main_unified_push_toast">המינוי הזה מנוהל על ידי %1$s דרך UnifiedPush</string>
<string name="add_dialog_use_another_server_description">נא למלא את כתובת השירותים להלן כדי להירשם לנושאים משרתים אחרים.</string>
<string name="add_dialog_button_login">כניסה</string>
<string name="add_dialog_error_connection_failed">החיבור נכשל: %1$s</string>
<string name="add_dialog_login_title">יש להיכנס</string>
<string name="add_dialog_login_username_hint">שם משתמש</string>
<string name="detail_delete_dialog_cancel">ביטול</string>
<string name="detail_test_title">בדיקה: אפשר להגדיר כותרת אם מתחשק לך.</string>
<string name="detail_test_message">זאת התראת בדיקה מהיישומון של ntfy ל־Android. רמת העדיפות שלו היא %1$d. אם תישלח התראה נוספת היא עשויה להיראות אחרת.</string>
<string name="detail_test_message_error">לא ניתן לשלוח הודעה: %1$s</string>
<string name="detail_test_message_error_unauthorized_anon">לא ניתן לשלוח הודעה: אסור לפרסם באופן אלמוני.</string>
<string name="share_successful">ההודעה פורסמה</string>
<string name="settings_notifications_channel_prefs_title">הגדרות ערוץ</string>
<string name="settings_notifications_auto_download_summary_never">לעולם לא להוריד צרופות אוטומטית</string>
<string name="settings_notifications_auto_download_summary_smaller_than_x">להוריד צרופות עד %1$s אוטומטית</string>
<string name="settings_notifications_auto_delete_summary_one_month">למחוק התראות אוטומטית לאחר חודש</string>
<string name="settings_notifications_auto_delete_summary_three_months">למחוק התראות אוטומטית לאחר 3 חודשים</string>
<string name="settings_notifications_auto_delete_never">אף פעם לא</string>
<string name="settings_notifications_auto_delete_one_day">לאחר יום</string>
<string name="settings_general_users_prefs_user_not_used">לא בשימוש של אף נושא</string>
<string name="settings_general_users_prefs_user_used_by_one">בשימוש הנושא %1$s</string>
<string name="settings_advanced_export_logs_copied_logs">היומן הועתק ללוח הגזירים</string>
<string name="settings_advanced_export_logs_entry_copy_original">העתקה ללוח הגזירים</string>
<string name="user_dialog_title_add">הוספת משתמש</string>
<string name="user_dialog_password_hint_add">סיסמה</string>
<string name="user_dialog_password_hint_edit">סיסמה (לא תשתנה אם יישאר ריק)</string>
<string name="user_dialog_button_add">הוספת משתמש</string>
<string name="detail_item_download_info_not_downloaded_expires_x">לא ירדה, התוקף יפוג ב־%1$s</string>
<string name="settings_notifications_auto_delete_title">מחיקת התראות</string>
<string name="settings_notifications_auto_delete_one_week">לאחר שבוע</string>
<string name="settings_advanced_connection_protocol_title">פרוטוקול חיבור</string>
<string name="settings_about_version_copied_to_clipboard_message">הועתק ללוח הגזירים</string>
<string name="settings_advanced_export_logs_title">העתקת/העלאת יומנים</string>
<string name="settings_advanced_export_logs_entry_upload_original">להעלות ולהעתיק קישור</string>
<string name="settings_advanced_export_logs_entry_upload_scrubbed">להעלות ולהעתיק קישור (מצונזר)</string>
<string name="detail_settings_appearance_icon_set_summary">נא להגדיר סמל שיוצג בהתראות</string>
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">הועתק ללוח הגזירים</string>
<string name="detail_settings_appearance_icon_remove_summary">סמל שמוצג בהתראות לנושא הזה</string>
<string name="add_dialog_instant_delivery_description">מוודא שהודעות נמסרות מיידית, אפילו אם המכשיר לא פעיל.</string>
<string name="add_dialog_button_subscribe">הרשמה</string>
<string name="add_dialog_button_back">חזרה</string>
<string name="add_dialog_button_cancel">ביטול</string>
<string name="detail_delete_dialog_permanently_delete">למחוק לצמיתות</string>
<string name="detail_copied_to_clipboard_message">הועתק ללוח הגזירים</string>
<string name="detail_item_snack_deleted">ההתראה נמחקה</string>
<string name="detail_item_menu_download">הורדת קובץ</string>
<string name="detail_item_menu_copy_url">העתקת כתובת</string>
<string name="detail_item_menu_copy_url_copied">הכתובת הועתקה ללוח הגזירים</string>
<string name="detail_item_menu_copy_contents">העתקת התראה</string>
<string name="detail_item_saved_successfully">נשמרה בשם „%1$s” בתיקיית ה„הורדות/Download”</string>
<string name="detail_item_menu_open">פתיחת קובץ</string>
<string name="share_content_file_text">שותף איתך קובץ</string>
<string name="settings_backup_restore_backup_entry_settings_only">הגדרות בלבד</string>
<string name="detail_item_cannot_open">אי אפשר לפתוח צרופה: %1$s</string>
<string name="detail_menu_unsubscribe">ביטול מינוי</string>
<string name="detail_action_mode_delete_dialog_message">למחוק את ההתראות הנבחרות לצמיתות?</string>
<string name="detail_action_mode_delete_dialog_permanently_delete">למחוק לצמיתות</string>
<string name="detail_action_mode_delete_dialog_cancel">ביטול</string>
<string name="detail_settings_title">הגדרות מינוי</string>
<string name="share_content_title">תצוגת הודעה מקדימה</string>
<string name="share_content_image_text">שותפה איתך תמונה</string>
<string name="share_content_image_error">לא ניתן לקרוא תמונה: %1$s</string>
<string name="share_content_file_error">לא ניתן לקרוא פרטי קובץ: %1$s</string>
<string name="settings_notifications_min_priority_summary_x_or_higher">להציג התראות אם העדיפות היא %1$d (%2$s) ומעלה</string>
<string name="notification_dialog_forever">עד לביטול ההשתקה</string>
<string name="settings_notifications_muted_until_title">השתקת התראות</string>
<string name="settings_notifications_auto_download_title">הורדות צרופות</string>
<string name="settings_notifications_channel_prefs_summary">מעקף „לא להפריע” (DND) צלילים וכו׳.</string>
<string name="settings_notifications_min_priority_low">עדיפות נמוכה ומעלה</string>
<string name="settings_notifications_priority_low">נמוכה</string>
<string name="settings_notifications_priority_max">מרבית</string>
<string name="settings_general_dark_mode_entry_light">מצב בהיר</string>
<string name="settings_notifications_priority_default">ברירת מחדל</string>
<string name="settings_notifications_priority_high">גבוהה</string>
<string name="settings_notifications_auto_download_always">להוריד הכול אוטומטית</string>
<string name="settings_notifications_auto_download_summary_always">להוריד את כל הצרופות אוטומטית</string>
<string name="settings_notifications_auto_download_never">לעולם לא להוריד כלום</string>
<string name="settings_notifications_auto_delete_summary_one_day">למחוק התראות אוטומטית לאחר יום</string>
<string name="settings_notifications_auto_delete_summary_three_days">למחוק התראות אוטומטית לאחר 3 ימים</string>
<string name="settings_notifications_auto_delete_summary_one_week">למחוק התראות אוטומטית לאחר שבוע</string>
<string name="settings_notifications_auto_delete_three_days">לאחר 3 ימים</string>
<string name="settings_general_dark_mode_entry_system">כמו המערכת</string>
<string name="settings_general_dark_mode_entry_dark">מצב כהה</string>
<string name="settings_backup_restore_restore_summary">ייבוא הגדרות, התראות ומשתמשים</string>
<string name="settings_backup_restore_restore_successful">השחזור הצליח</string>
<string name="detail_item_download_info_download_failed">ההורדה נכשלה</string>
<string name="settings_advanced_broadcast_summary_disabled">יישומונים לא יכולים לקבל התראות כשידורים</string>
<string name="settings_advanced_unifiedpush_title">הפעלת UnifiedPush</string>
<string name="settings_advanced_unifiedpush_summary_enabled">ntfy ישמש כמפיץ UnifiedPush</string>
<string name="settings_about_version_title">גרסה</string>
<string name="settings_advanced_connection_protocol_entry_ws">WebSockets</string>
<string name="settings_advanced_connection_protocol_entry_jsonhttp">תזרים JSON על גבי HTTP</string>
<string name="settings_about_header">על אודות</string>
<string name="settings_about_version_format">ntfy %1$s (%2$s)</string>
<string name="detail_settings_appearance_icon_remove_title">סמל מינוי (נגיעה להסרה)</string>
<string name="detail_settings_appearance_icon_error_saving">לא ניתן לשמור סמל: %1$s</string>
<string name="detail_settings_appearance_display_name_title">שם תצוגה</string>
<string name="detail_settings_appearance_display_name_default_summary">%1$s (ברירת מחדל)</string>
<string name="detail_settings_about_header">על אודות</string>
<string name="detail_settings_about_topic_url_title">כתובת נושא</string>
<string name="user_dialog_title_edit">עריכת משתמש</string>
<string name="user_dialog_description_add">כאן אפשר להוסיף משתמש. כל הנושאים לשרת שצוין ישתמשו במשתמש הזה.</string>
<string name="user_dialog_description_edit">אפשר לערוך שם משתמש/סיסמה למשתמש הנבחר או למחוק אותו.</string>
<string name="user_dialog_base_url_hint">כתובת שירות</string>
<string name="user_dialog_username_hint">שם משתמש</string>
<string name="user_dialog_button_cancel">ביטול</string>
<string name="user_dialog_button_delete">מחיקת משתמש</string>
<string name="user_dialog_button_save">שמירה</string>
<string name="detail_item_cannot_delete">לא ניתן למחוק צרופה: %1$s</string>
<string name="detail_item_download_failed">לא ניתן להוריד צרופה: %1$s</string>
<string name="detail_item_download_info_not_downloaded_expired">לא ירדה, תוקף הקישור פג</string>
<string name="detail_item_download_info_deleted_expires_x">נמחקה, הקישור יפוג ב־%1$s</string>
<string name="detail_item_download_info_download_failed_expired">ההורדה נכשלה, תוקף הקישור פג</string>
<string name="detail_menu_notifications_enabled">התראות פעילות</string>
<string name="settings_advanced_export_logs_entry_copy_scrubbed">העתקה ללוח הגזירים (מצונזר)</string>
<string name="settings_advanced_export_logs_uploading">היומן נשלח…</string>
<string name="settings_advanced_clear_logs_deleted_toast">יומנים נמחקו</string>
<string name="detail_settings_notifications_open_channels_title">הגדרות תצורת התראות</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_disabled">להודיע רק פעם אחת</string>
<string name="main_banner_websocket_text">החלפה ל־WebSockets היא הדרך המומלצת להתחבר לשרת שלך ויכולה לשפר את חייה הסוללה אך היא עשויה לדרוש <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">שינויים נוספים במתווך שלך</a>. אפשר להפעיל או לכבות את זה בהגדרות.</string>
<string name="settings_notifications_insistent_max_priority_title">להמשיך להודיע לעדיפות הגבוהה ביותר</string>
<string name="detail_item_cannot_open_not_found">לא ניתן לפתוח את הצרופה: יכול להיות שהקובץ נמחק או שאין יישומון מותקן שיכול לפתוח את הקובץ.</string>
<string name="detail_item_cannot_open_url">לא ניתן לפתוח כתובת: %1$s</string>
<string name="notification_popup_file_downloading">בהורדה%1$s, %2$d%%
\n%3$s</string>
<string name="detail_item_cannot_open_apk">אי אפשר להתקין עוד יישומונים. יש להוריד דרך הדפדפן במקום. בתקלה #531 מופיעים פרטים נוספים.</string>
<string name="detail_settings_global_setting_suffix">נעשה שימוש בהגדרות גלובליות</string>
</resources>

View file

@ -1,29 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="channel_notifications_min_name">優先度 最低</string>
<string name="channel_notifications_min_name">通知 (優先度最低)</string>
<string name="detail_delete_dialog_cancel">キャンセル</string>
<string name="detail_menu_notifications_enabled">通知オン</string>
<string name="settings_notifications_auto_download_summary_never">添付ファイルは自動的にダウンロードしない</string>
<string name="settings_notifications_auto_download_never">自動ダウンロードしない</string>
<string name="settings_notifications_auto_download_5m">5MB未満はダウンロード</string>
<string name="settings_notifications_auto_download_10m">10MB未満はダウンロード</string>
<string name="settings_notifications_auto_download_5m">5MB未満の場合</string>
<string name="settings_notifications_auto_download_10m">10MB未満の場合</string>
<string name="settings_notifications_auto_delete_one_day">1日後</string>
<string name="settings_notifications_auto_delete_three_days">3日後</string>
<string name="settings_notifications_auto_delete_one_week">1週間後</string>
<string name="settings_notifications_auto_delete_one_month">1か月後</string>
<string name="settings_advanced_connection_protocol_entry_ws">WebSockets</string>
<string name="channel_notifications_high_name">優先度 </string>
<string name="channel_notifications_default_name">優先度 通常</string>
<string name="channel_notifications_high_name">通知 (優先度高)</string>
<string name="channel_notifications_default_name">通知 (優先度通常)</string>
<string name="channel_subscriber_notification_noinstant_text_two">トピックを2件購読しています</string>
<string name="add_dialog_login_new_user">新規ユーザー</string>
<string name="channel_notifications_max_name">優先度 最高</string>
<string name="channel_notifications_max_name">通知 (優先度最高)</string>
<string name="channel_subscriber_notification_instant_text_two">即時配信トピックを2件購読しています</string>
<string name="channel_notifications_low_name">優先度 </string>
<string name="channel_notifications_low_name">通知 (優先度低)</string>
<string name="channel_subscriber_notification_title">通知の受信を待機しています</string>
<string name="channel_subscriber_notification_instant_text">即時配信トピックを購読しています</string>
<string name="channel_subscriber_service_name">購読サービス</string>
<string name="channel_subscriber_notification_instant_text_three">即時配信トピックを3件購読しています</string>
<string name="main_menu_notifications_disabled_until">通知を%1$sまでミュート</string>
<string name="main_menu_notifications_disabled_until">通知を%1$sまで停止</string>
<string name="main_menu_rate_title">アプリを評価⭐</string>
<string name="main_item_status_text_not_one">通知 %1$d件</string>
<string name="add_dialog_button_cancel">キャンセル</string>
@ -37,7 +37,7 @@
<string name="refresh_message_error">%1$d件の購読を更新できませんでした
\n
\n%2$s</string>
<string name="main_action_bar_title">購読したトピック</string>
<string name="main_action_bar_title">トピックを購読しました</string>
<string name="channel_subscriber_notification_instant_text_four">即時配信トピックを4件購読しています</string>
<string name="channel_subscriber_notification_noinstant_text_one">トピックを1件購読しています</string>
<string name="main_menu_notifications_enabled">通知オン</string>
@ -67,8 +67,10 @@
<string name="add_dialog_title">トピックを購読</string>
<string name="add_dialog_button_login">ログイン</string>
<string name="add_dialog_login_error_not_authorized">ログインに失敗しました。ユーザー名 %1$s は許可されていません。</string>
<string name="main_banner_websocket_button_remind_later">後で通知</string>
<string name="main_banner_websocket_button_dismiss">無視</string>
<string name="main_banner_json_stream_button_remind_later">後で通知</string>
<string name="main_banner_json_stream_button_dismiss">無視</string>
<string name="main_banner_json_stream_button_learn_more">詳しく</string>
<string name="main_banner_json_stream_text">2022年6月以降もセルフホストのntfyサーバーと通信できるように、設定の「接続プロトコル」をWebSocketsに変更してください。</string>
<string name="add_dialog_description_below">トピックはパスワード保護されないので、推測されにくい名前にしてください。購読した後、PUT/POSTで通知を送信できます。</string>
<string name="add_dialog_instant_delivery">Dozeモードでの即時配信</string>
<string name="add_dialog_instant_delivery_description">デバイスが非アクティブの状態でもメッセージが即時配信されるようにします。</string>
@ -83,7 +85,7 @@
<string name="add_dialog_login_description">このトピックはログインする必要があります。ユーザー名とパスワードを入力してください。</string>
<string name="detail_test_message_error">メッセージを送信できませんでした: %1$s</string>
<string name="detail_test_message_error_unauthorized_anon">メッセージを送信できませんでした: 匿名送信は許可されていません。</string>
<string name="detail_no_notifications_text">このトピックの通知まだ受信していません。</string>
<string name="detail_no_notifications_text">このトピックの通知まだ受信していません。</string>
<string name="detail_how_to_link">詳細な説明は ntfy.sh またはドキュメントを参照してください。</string>
<string name="detail_clear_dialog_permanently_delete">完全に削除</string>
<string name="detail_delete_dialog_message">このトピックの購読を解除して受信した通知をすべて削除しますか?</string>
@ -119,7 +121,7 @@
<string name="detail_item_menu_save_file">ファイルを保存</string>
<string name="detail_item_menu_copy_url">URLをコピー</string>
<string name="detail_item_cannot_open_not_found">添付ファイルを開けません: ファイルが削除されているか、ファイルを開けるアプリがインストールされていません。</string>
<string name="detail_item_cannot_open_url">URLを開けません: %1$s</string>
<string name="detail_item_cannot_open_click_url">URLを開けません: %1$s</string>
<string name="detail_item_cannot_save">添付ファイルを保存できません: %1$s</string>
<string name="detail_item_download_failed">添付ファイルをダウンロードできません: %1$s</string>
<string name="detail_item_download_info_deleted">削除済</string>
@ -128,9 +130,9 @@
<string name="detail_item_download_info_not_downloaded_expires_x">未ダウンロード、リンク失効期限 %1$s</string>
<string name="detail_item_download_info_download_failed_expired">ダウンロード失敗、リンク失効後</string>
<string name="detail_item_download_info_download_failed_expires_x">ダウンロード失敗、リンク失効期限 %1$s</string>
<string name="detail_menu_notifications_disabled_forever">通知をミュート</string>
<string name="detail_menu_notifications_disabled_forever">通知一時停止</string>
<string name="detail_menu_disable_instant">即時配信をオフにする</string>
<string name="detail_menu_notifications_disabled_until">通知 %1$s までミュート</string>
<string name="detail_menu_notifications_disabled_until">通知 %1$s まで停止</string>
<string name="detail_menu_enable_instant">即時配信をオンにする</string>
<string name="detail_menu_clear">全ての通知を消去</string>
<string name="share_menu_send">共有</string>
@ -163,23 +165,23 @@
<string name="share_successful">メッセージが送信されました</string>
<string name="notification_dialog_cancel">キャンセル</string>
<string name="notification_dialog_save">保存</string>
<string name="notification_dialog_title">通知をミュート</string>
<string name="notification_dialog_title">通知を停止</string>
<string name="share_suggested_topics">提案されたトピック</string>
<string name="notification_dialog_muted_forever_toast_message">通知をミュートしました</string>
<string name="notification_dialog_30min">30分</string>
<string name="notification_dialog_muted_forever_toast_message">通知を停止しました</string>
<string name="notification_dialog_30min">30分</string>
<string name="notification_dialog_8h">8時間</string>
<string name="notification_dialog_tomorrow">明日まで</string>
<string name="notification_popup_action_download">ダウンロード</string>
<string name="notification_dialog_enabled_toast_message">通知を再開しました</string>
<string name="notification_dialog_show_all">全ての通知を表示</string>
<string name="notification_popup_action_browse">ブラウズ</string>
<string name="notification_dialog_muted_until_toast_message">通知を %1$s までミュートします</string>
<string name="notification_dialog_muted_until_toast_message">通知を %1$s まで停止します</string>
<string name="notification_dialog_2h">2時間</string>
<string name="notification_popup_action_cancel">キャンセル</string>
<string name="notification_popup_file_downloading">%1$sをダウンロード中、%2$d%%
\n%3$s</string>
<string name="main_menu_notifications_disabled_forever">通知をミュート</string>
<string name="settings_notifications_muted_until_forever">再開されるまで通知ミュート</string>
<string name="main_menu_notifications_disabled_forever">通知を停止</string>
<string name="settings_notifications_muted_until_forever">再開されるまで通知は停止</string>
<string name="notification_popup_file">%1$s
\nファイル: %2$s</string>
<string name="notification_popup_file_download_successful">%1$s
@ -187,25 +189,25 @@
<string name="notification_popup_file_download_failed">%1$s
\nファイル: %2$s ダウンロード失敗</string>
<string name="settings_title">設定</string>
<string name="settings_notifications_muted_until_title">通知をミュート</string>
<string name="settings_notifications_muted_until_title">通知を停止</string>
<string name="settings_notifications_muted_until_show_all">全ての通知を表示します</string>
<string name="settings_notifications_muted_until_x">%1$s まで通知をミュート</string>
<string name="settings_notifications_muted_until_x">%1$s まで通知を停止</string>
<string name="settings_notifications_min_priority_summary_x_or_higher">優先度が %1$d (%2$s) 以上の場合のみ通知を表示します</string>
<string name="settings_notifications_min_priority_min">全ての優先度</string>
<string name="settings_notifications_priority_max">最高</string>
<string name="settings_notifications_auto_download_summary_always">全ての添付ファイルを自動的にダウンロード</string>
<string name="settings_notifications_min_priority_max">優先度最高のみ</string>
<string name="settings_notifications_auto_download_summary_smaller_than_x">最大%1$sまで自動的にダウンロード</string>
<string name="settings_notifications_auto_download_100k">100kB未満はダウンロード</string>
<string name="settings_notifications_auto_download_500k">500kB未満はダウンロード</string>
<string name="settings_notifications_auto_download_1m">1MB未満はダウンロード</string>
<string name="settings_notifications_auto_download_summary_smaller_than_x">最大%1$sまで自動的にダウンロード</string>
<string name="settings_notifications_auto_download_100k">100kB未満の場合</string>
<string name="settings_notifications_auto_download_500k">500kB未満の場合</string>
<string name="settings_notifications_auto_download_1m">1MB未満の場合</string>
<string name="settings_notifications_min_priority_default">優先度通常 およびそれ以上</string>
<string name="settings_general_users_prefs_user_not_used">どのトピックにも使用されていません</string>
<string name="settings_notifications_auto_delete_three_months">3か月後</string>
<string name="settings_general_dark_mode_summary_dark">ダークモード有効。もしかして吸血鬼ですか</string>
<string name="settings_general_dark_mode_summary_dark">ダークモード有効。もしかして吸血鬼?</string>
<string name="settings_notifications_auto_download_title">添付ファイルのダウンロード</string>
<string name="settings_notifications_auto_download_always">全てを自動ダウンロードする</string>
<string name="settings_notifications_auto_download_50m">50MB未満はダウンロード</string>
<string name="settings_notifications_auto_download_50m">50MB未満の場合</string>
<string name="settings_notifications_auto_delete_summary_never">通知を自動的に削除しない</string>
<string name="settings_notifications_auto_delete_title">通知を削除</string>
<string name="settings_notifications_auto_delete_summary_one_month">1か月後に通知を自動削除する</string>
@ -269,7 +271,7 @@
<string name="settings_advanced_export_logs_copied_logs">ログをクリップボードにコピーしました</string>
<string name="settings_advanced_export_logs_error_uploading">ログをアップロードできませんでした: %1$s</string>
<string name="settings_advanced_export_logs_scrub_dialog_empty">トピック名/ホスト名は編集されていません。ひとつも購読していませんか?</string>
<string name="settings_advanced_connection_protocol_summary_ws">サーバーへの接続にWebSocketsを使用します。推奨されるメソッドですが、プロキシに追加設定を必要とします。</string>
<string name="settings_advanced_connection_protocol_summary_ws">サーバーへの接続にWebSocketsを使用します。2022年6月からはデフォルト設定になります。</string>
<string name="settings_about_header">About</string>
<string name="settings_about_version_format">ntfy %1$s (%2$s)</string>
<string name="user_dialog_title_edit">ユーザーを編集</string>
@ -282,7 +284,7 @@
<string name="settings_advanced_connection_protocol_entry_jsonhttp">JSON stream over HTTP</string>
<string name="settings_advanced_clear_logs_summary">これまで記録されたログを消去し、再開します</string>
<string name="settings_advanced_clear_logs_deleted_toast">ログが削除されました</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">サーバーへの接続に JSON stream over HTTP を使用します。このメソッドは様々な場面で使われていますが、バッテリーをより多く消費します。</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">サーバーへの接続に JSON stream over HTTP を使用します。このメソッドは非推奨で、2022年6月に削除されます。</string>
<string name="settings_about_version_copied_to_clipboard_message">クリップボードにコピーしました</string>
<string name="user_dialog_title_add">ユーザーを追加</string>
<string name="user_dialog_description_edit">選択されたユーザーのユーザー名/パスワードを変更または削除できます。</string>
@ -299,48 +301,4 @@
<string name="settings_notifications_min_priority_title">表示する優先度</string>
<string name="add_dialog_topic_name_hint">トピック名, 例) phils_alerts</string>
<string name="detail_deep_link_subscribed_toast_message">トピック %1$s を購読しました</string>
<string name="settings_notifications_channel_prefs_title">チャネル設定</string>
<string name="settings_notifications_channel_prefs_summary">おやすみモード時の動作やサウンド等を設定します。</string>
<string name="notification_popup_user_action_failed">%1$s 失敗: %2$s</string>
<string name="channel_subscriber_notification_noinstant_text_six">トピックを6件購読しています</string>
<string name="detail_settings_appearance_header">外観</string>
<string name="detail_settings_appearance_icon_set_title">購読アイコン</string>
<string name="detail_settings_appearance_icon_error_saving">アイコンを保存できませんでした: %1$s</string>
<string name="detail_settings_global_setting_suffix">グローバル設定を使用中</string>
<string name="detail_settings_global_setting_title">グローバル設定を使用する</string>
<string name="detail_settings_appearance_icon_remove_title">購読アイコン (タップして削除)</string>
<string name="channel_subscriber_notification_instant_text_five">即時配信トピックを5件購読しています</string>
<string name="channel_subscriber_notification_instant_text_six">即時配信トピックを6件購読しています</string>
<string name="detail_settings_notifications_instant_title">即時配信</string>
<string name="detail_settings_appearance_icon_remove_summary">このトピックの通知で表示されるアイコン</string>
<string name="detail_settings_notifications_instant_summary_on">通知は即時配信されます。フォアグラウンドサービスの実行が必要で、バッテリーを多く消費します。</string>
<string name="detail_settings_notifications_instant_summary_off">通知はFirebaseを用いて配信されます。配信が遅延する事がありますが、バッテリーの消費は抑えられます。</string>
<string name="detail_settings_appearance_icon_set_summary">通知に表示されるアイコンを指定します</string>
<string name="channel_subscriber_notification_noinstant_text_five">トピックを5件購読しています</string>
<string name="detail_settings_appearance_display_name_title">表示名</string>
<string name="detail_settings_appearance_display_name_default_summary">%1$s (デフォルト)</string>
<string name="detail_settings_appearance_display_name_message">この購読のカスタム表示名を設定します。空欄でデフォルト (%1$s) が表示されます。</string>
<string name="add_dialog_base_urls_dropdown_choose">サービスURLを選択</string>
<string name="add_dialog_base_urls_dropdown_clear">サービスURLをクリア</string>
<string name="main_banner_websocket_text">WebSocketへの切り替えはサーバーへの接続方法として推奨され、バッテリー寿命を改善できる可能性がありますが、<a href="https://ntfy.sh/docs/config/#nginxapache2caddy">プロクシへの追加設定</a>が必要となります。設定から切り替えることができます。</string>
<string name="main_banner_websocket_button_enable_now">今すぐ有効化</string>
<string name="detail_settings_about_header">About</string>
<string name="detail_settings_about_topic_url_title">トピックのURL</string>
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">クリップボードにコピーしました</string>
<string name="main_menu_donate_title">寄付する💸</string>
<string name="detail_item_cannot_open_apk">アプリはインストールできなくなりました。代替手段としてブラウザからダウンロードしてください。詳細は issue #531 をご参照ください。</string>
<string name="settings_notifications_insistent_max_priority_summary_enabled">優先度最高は非表示になるまで通知継続</string>
<string name="channel_notifications_group_default_name">デフォルト</string>
<string name="settings_notifications_insistent_max_priority_title">優先度最高は通知継続</string>
<string name="settings_notifications_insistent_max_priority_summary_disabled">優先度最高は一回のみ通知</string>
<string name="detail_settings_notifications_dedicated_channels_title">カスタム通知設定</string>
<string name="detail_settings_notifications_open_channels_title">通知設定を編集</string>
<string name="detail_settings_notifications_dedicated_channels_summary_off">デフォルト設定を使用(サウンドやおやすみモード時の動作等)</string>
<string name="detail_settings_notifications_open_channels_summary">おやすみモード時の動作やサウンド等</string>
<string name="detail_settings_notifications_dedicated_channels_summary_on">この購読にカスタム設定を利用</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_enabled">通知を継続</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_disabled">一回のみ通知</string>
<string name="settings_advanced_unifiedpush_summary_enabled">ntfyがUnifiedPushディストリビュータとして振る舞うようになります</string>
<string name="settings_advanced_unifiedpush_summary_disabled">ntfyはUnifiedPushディストリビュータとして振る舞いません</string>
<string name="settings_advanced_unifiedpush_title">UnifiedPushを有効化する</string>
</resources>

View file

@ -1,330 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="detail_how_to_link">자세한 설명은 ntfy.sh와 docs 페이지에서 찾으실 수 있습니다.</string>
<string name="channel_notifications_high_name">알림 (우선순위 높음)</string>
<string name="main_menu_notifications_disabled_forever">알림 음소거됨</string>
<string name="channel_subscriber_notification_instant_text_three">즉시 전달 주제 3개 구독중</string>
<string name="add_dialog_use_another_server">다른 서버 사용</string>
<string name="main_menu_notifications_enabled">알림 켜짐</string>
<string name="channel_notifications_default_name">알림 (우선순위 기본)</string>
<string name="channel_notifications_max_name">알림 (우선순위 최상)</string>
<string name="channel_subscriber_service_name">구독 서비스</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_six">즉시 전달 주제 6개 구독중</string>
<string name="channel_subscriber_notification_instant_text_more">즉시 전달 주제 %1$d개 구독중</string>
<string name="channel_subscriber_notification_noinstant_text">주제 구독중</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_three">주제 3개 구독 중</string>
<string name="channel_subscriber_notification_noinstant_text_more">주제 %1$d개 구독 중</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_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_status_reconnecting">재연결중 …</string>
<string name="main_no_subscriptions_text">아직 아무런 구독을 추가하지 않으신 것 같습니다.</string>
<string name="main_how_to_link">자세한 설명은 ntfy.sh와 docs 페이지에서 찾으실 수 있습니다.</string>
<string name="main_unified_push_toast">이 구독은 UnifiedPush를 통해 %1$s에서 관리됩니다</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_foreground_description">%1$s 이외 서버에서는 즉시 알림을 끌 수 없습니다.</string>
<string name="add_dialog_button_cancel">취소</string>
<string name="add_dialog_button_subscribe">구독하기</string>
<string name="add_dialog_button_back">뒤로가기</string>
<string name="add_dialog_button_login">로그인</string>
<string name="add_dialog_error_connection_failed">연결 실패: %1$s</string>
<string name="add_dialog_login_title">로그인 필요함</string>
<string name="add_dialog_login_description">이 주제는 로그인이 필요합니다. 사용자 이름과 비밀번호를 입력해 주세요.</string>
<string name="add_dialog_login_username_hint">사용자 이름</string>
<string name="add_dialog_login_password_hint">비밀번호</string>
<string name="add_dialog_login_error_not_authorized">로그인 실패. 사용자 %1$s은(는) 인증되지 않았습니다.</string>
<string name="add_dialog_login_new_user">사용자 추가</string>
<string name="detail_no_notifications_text">아직 이 주제 관련 알림을 받지 않았습니다.</string>
<string name="detail_clear_dialog_permanently_delete">영구 삭제</string>
<string name="detail_clear_dialog_cancel">취소</string>
<string name="detail_delete_dialog_message">이 주제를 구독 해제하고 모든 알림을 삭제하시겠습니까\?</string>
<string name="detail_test_message_error">메세지를 보낼 수 없습니다: %1$s</string>
<string name="detail_test_message_error_unauthorized_anon">메세지를 보낼 수 없습니다: 익명 발송이 허용되지 않습니다.</string>
<string name="detail_test_message_error_unauthorized_user">메세지를 보낼 수 없습니다: 사용자 \"%1$s\"은(는) 인증되지 않았습니다.</string>
<string name="detail_test_message_error_too_large">메세지를 보낼 수 없습니다: 첨부 파일이 너무 큽니다.</string>
<string name="detail_item_tags">태그: %1$s</string>
<string name="detail_item_snack_deleted">알림 삭제됨</string>
<string name="detail_item_menu_copy_url">URL 복사</string>
<string name="detail_item_cannot_open">첨부 파일을 열 수 없습니다: %1$s</string>
<string name="detail_item_cannot_open_not_found">첨부 파일을 열 수 없습니다: 파일이 삭제되었거나 파일을 열 수 있는 앱이 없습니다.</string>
<string name="detail_menu_enable_instant">즉시 전달 켜기</string>
<string name="detail_menu_disable_instant">즉시 전달 끄기</string>
<string name="detail_menu_clear">모든 알림 초기화</string>
<string name="share_menu_send">공유</string>
<string name="share_content_text_hint">여기에 공유할 내용 추가</string>
<string name="share_content_image_text">이미지가 공유됨</string>
<string name="share_successful">메세지 발송됨</string>
<string name="notification_dialog_title">알림 음소거</string>
<string name="notification_dialog_cancel">취소</string>
<string name="notification_popup_action_open">열기</string>
<string name="notification_popup_action_browse">탐색</string>
<string name="notification_popup_action_download">다운로드</string>
<string name="notification_popup_action_cancel">취소</string>
<string name="notification_popup_file">%1$s
\n파일: %2$s</string>
<string name="notification_popup_file_downloading">%1$s 다운로드중, %2$d%%
\n%3$s</string>
<string name="notification_popup_file_download_successful">%1$s
\n파일: %2$s, 다운로드됨</string>
<string name="notification_popup_file_download_failed">%1$s
\n파일: %2$s, 다운로드 실패</string>
<string name="notification_popup_user_action_failed">%1$s 실패: %2$s</string>
<string name="settings_title">설정</string>
<string name="settings_notifications_header">알림</string>
<string name="settings_notifications_muted_until_title">알림 음소거</string>
<string name="settings_notifications_muted_until_show_all">모든 알림 표시</string>
<string name="settings_notifications_muted_until_forever">해제시까지 알림 음소거</string>
<string name="settings_notifications_muted_until_x">%1$s까지 알림 음소거</string>
<string name="settings_notifications_min_priority_title">최소 우선순위</string>
<string name="settings_notifications_min_priority_summary_any">모든 알림 보기</string>
<string name="settings_notifications_min_priority_summary_x_or_higher">우선순위가 %1$d (%2$s) 보다 높은 알림만 보기</string>
<string name="settings_notifications_min_priority_summary_max">우선순위가 5 (최상) 인 알림만 보기</string>
<string name="settings_notifications_min_priority_min">아무 우선순위</string>
<string name="settings_notifications_min_priority_low">낮음 이상</string>
<string name="settings_notifications_min_priority_default">기본 이상</string>
<string name="settings_notifications_min_priority_high">높음 이상</string>
<string name="settings_notifications_min_priority_max">최상</string>
<string name="settings_notifications_priority_min">최하</string>
<string name="settings_notifications_priority_low">낮음</string>
<string name="settings_notifications_priority_default">기본</string>
<string name="settings_notifications_priority_high">높음</string>
<string name="settings_notifications_priority_max">최상</string>
<string name="settings_notifications_channel_prefs_title">채널 설정</string>
<string name="settings_notifications_channel_prefs_summary">방해 금지 모드 무시하기, 소리, 기타 설정.</string>
<string name="settings_notifications_auto_download_summary_always">모든 첨부 파일을 자동 다운로드</string>
<string name="settings_notifications_auto_download_title">첨부 파일 다운로드</string>
<string name="settings_notifications_auto_download_summary_never">첨부 파일을 자동으로 다운로드하지 않음</string>
<string name="settings_notifications_auto_download_summary_smaller_than_x">첨부 파일 크기가 %1$s보다 작다면 자동 다운로드</string>
<string name="settings_notifications_auto_download_never">어떤 파일도 자동으로 다운로드하지 않음</string>
<string name="settings_notifications_auto_download_always">모든 파일을 자동으로 다운로드</string>
<string name="settings_notifications_auto_download_100k">100kB보다 작다면</string>
<string name="settings_notifications_auto_download_500k">500kB보다 작다면</string>
<string name="settings_notifications_auto_download_1m">1MB보다 작다면</string>
<string name="settings_notifications_auto_download_5m">5MB보다 작다면</string>
<string name="settings_notifications_auto_download_10m">10MB보다 작다면</string>
<string name="settings_notifications_auto_delete_title">알림 삭제</string>
<string name="settings_notifications_auto_delete_summary_one_day">알림을 1일 뒤 자동으로 삭제함</string>
<string name="settings_notifications_auto_delete_summary_three_days">알림을 3일 뒤 자동으로 삭제함</string>
<string name="settings_notifications_auto_delete_summary_one_week">알림을 1주 뒤 자동으로 삭제함</string>
<string name="settings_notifications_auto_delete_summary_three_months">알림을 3달 뒤 자동으로 삭제함</string>
<string name="settings_notifications_auto_delete_never">자동 삭제 안함</string>
<string name="settings_notifications_auto_delete_one_day">1일 뒤</string>
<string name="settings_notifications_auto_delete_three_days">3일 뒤</string>
<string name="settings_notifications_auto_delete_one_week">1주 뒤</string>
<string name="settings_notifications_auto_delete_one_month">1달 뒤</string>
<string name="settings_notifications_auto_delete_three_months">3달 뒤</string>
<string name="settings_general_header">일반</string>
<string name="settings_general_default_base_url_title">기본 서버</string>
<string name="settings_general_default_base_url_default_summary">%1$s (기본)</string>
<string name="settings_general_dark_mode_title">다크 모드</string>
<string name="settings_general_dark_mode_summary_system">시스템 설정 사용중</string>
<string name="settings_general_dark_mode_summary_light">라이트 모드 사용중</string>
<string name="settings_general_dark_mode_summary_dark">다크 모드 사용중. 혹시 뱀파이어신가요\?</string>
<string name="settings_general_dark_mode_entry_system">시스템 설정 사용</string>
<string name="settings_general_dark_mode_entry_light">라이트 모드</string>
<string name="settings_general_dark_mode_entry_dark">다크 모드</string>
<string name="settings_backup_restore_header">백업 및 복원</string>
<string name="settings_backup_restore_backup_title">파일에 백업</string>
<string name="settings_backup_restore_backup_summary">설정, 알림, 사용자 내보내기</string>
<string name="settings_backup_restore_backup_entry_everything">모두</string>
<string name="settings_backup_restore_restore_summary">설정, 알림, 사용자 가져오기</string>
<string name="settings_backup_restore_restore_successful">복원 성공</string>
<string name="settings_backup_restore_restore_failed">복원 실패: %1$s</string>
<string name="settings_advanced_header">고급 설정</string>
<string name="settings_advanced_broadcast_summary_disabled">앱이 들어오는 알림을 브로드캐스트할 수 없습니다</string>
<string name="settings_advanced_record_logs_title">로그 기록</string>
<string name="settings_advanced_export_logs_summary">로그를 클립보드에 복사하거나 nopaste.net(ntfy 소유주가 운영하는)에 업로드합니다. 서버 주소나 주제는 가려지지만 알림은 가려지지 않습니다.</string>
<string name="settings_advanced_export_logs_entry_copy_original">클립보드에 복사</string>
<string name="settings_advanced_export_logs_entry_copy_scrubbed">클립보드에 복사 (검열본)</string>
<string name="settings_advanced_export_logs_copied_url">로그가 업로드되고 링크를 복사했습니다</string>
<string name="settings_advanced_export_logs_scrub_dialog_empty">어떠한 주제/서버 이름도 검열되지 않았습니다. 구독이 없던 것은 아닌가요\?</string>
<string name="settings_advanced_clear_logs_deleted_toast">로그 삭제됨</string>
<string name="settings_advanced_connection_protocol_title">연결 프로토콜</string>
<string name="settings_advanced_connection_protocol_entry_jsonhttp">JSON stream over HTTP</string>
<string name="detail_settings_appearance_header">표시 설정</string>
<string name="channel_notifications_low_name">알림 (우선순위 낮음)</string>
<string name="user_dialog_button_save">저장</string>
<string name="channel_notifications_min_name">알림 (우선순위 최하)</string>
<string name="channel_subscriber_notification_instant_text_two">즉시 전달 주제 2개 구독중</string>
<string name="channel_subscriber_notification_instant_text_five">즉시 전달 주제 5개 구독중</string>
<string name="channel_subscriber_notification_instant_text_four">즉시 전달 주제 4개 구독중</string>
<string name="channel_subscriber_notification_noinstant_text_four">주제 4개 구독 중</string>
<string name="main_menu_report_bug_title">버그 제보</string>
<string name="add_dialog_topic_name_hint">주제 이름, 예를 들어 phils_alerts</string>
<string name="add_dialog_use_another_server_description">알림을 받을 서버의 주소를 아래에 입력해주세요.</string>
<string name="add_dialog_instant_delivery">대기 상태에서 즉시 알림 받기</string>
<string name="detail_clear_dialog_message">이 주제의 모든 알림을 삭제하시겠습니까\?</string>
<string name="channel_subscriber_notification_noinstant_text_five">주제 5개 구독 중</string>
<string name="channel_subscriber_notification_noinstant_text_six">주제 6개 구독 중</string>
<string name="main_menu_notifications_disabled_until">알림 %1$s까지 음소거됨</string>
<string name="main_menu_settings_title">설정</string>
<string name="main_menu_docs_title">문서 보기</string>
<string name="main_menu_rate_title">앱 평가하기 ⭐</string>
<string name="main_how_to_intro">+ 버튼을 눌러 주제를 구독할 수 있습니다. 이후 장치에서 PUT이나 POST를 통해 보내진 알림을 받을 수 있습니다.</string>
<string name="main_item_status_unified_push">%1$s (UnifiedPush)</string>
<string name="main_item_date_yesterday">어제</string>
<string name="main_add_button_description">구독 추가</string>
<string name="main_banner_websocket_text">웹소켓으로 연결하는 방법이 권장하는 방법이며 배터리 수명을 증가시킬수 있지만, 서버에 따라 <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">추가 설정</a>이 필요할 수 있습니다. 이것은 설정에서 변경 가능합니다.</string>
<string name="add_dialog_instant_delivery_description">장치가 활성화되지 않은 상태에서도 알림을 즉시 받을수 있도록 합니다.</string>
<string name="detail_delete_dialog_permanently_delete">영구 삭제</string>
<string name="detail_delete_dialog_cancel">취소</string>
<string name="detail_instant_delivery_enabled">즉시 전달 켜짐</string>
<string name="add_dialog_base_urls_dropdown_clear">서비스 URL 초기화</string>
<string name="detail_how_to_intro">알림을 받으려면 아래 주소로 PUT이나 POST 요청을 보내세요.</string>
<string name="detail_deep_link_subscribed_toast_message">주제 %1$s 를 구독했습니다</string>
<string name="detail_item_menu_cancel">다운로드 취소</string>
<string name="detail_item_menu_copy_contents_copied">알림이 클립보드로 복사됨</string>
<string name="detail_item_cannot_save">첨부 파일을 저장할 수 없습니다: %1$s</string>
<string name="detail_item_cannot_delete">첨부 파일을 삭제할 수 없습니다: %1$s</string>
<string name="share_content_title">메세지 미리보기</string>
<string name="notification_dialog_muted_forever_toast_message">알림 음소거됨</string>
<string name="notification_dialog_show_all">모든 알림 보기</string>
<string name="detail_test_message">이것은 ntfy 안드로이드 앱에서 보낸 시험용 알림입니다. 우선순위는 %1$d입니다. 다시 알림을 보낸다면 다르게 보일 수 있습니다.</string>
<string name="detail_item_snack_undo">실행 취소</string>
<string name="detail_item_menu_delete">파일 삭제</string>
<string name="detail_item_menu_download">파일 다운로드</string>
<string name="detail_item_cannot_download">첨부 파일을 열거나 다운로드할 수 없습니다. 링크가 만료되었으며 로컬 사본을 찾을 수 없습니다.</string>
<string name="settings_general_users_prefs_user_used_by_one">주제 %1$s에서 사용됨</string>
<string name="settings_about_version_copied_to_clipboard_message">클립보드에 복사됨</string>
<string name="detail_settings_global_setting_title">전역 설정 사용하기</string>
<string name="detail_copied_to_clipboard_message">클립보드에 복사됨</string>
<string name="detail_item_menu_open">파일 열기</string>
<string name="detail_item_menu_copy_url_copied">URL이 클립보드에 복사됨</string>
<string name="add_dialog_base_urls_dropdown_choose">서비스 URL 선택</string>
<string name="detail_how_to_example">예제 (curl 사용):<br/><tt>$ curl -d \\\"Hi\\\" %1$s</tt></string>
<string name="share_content_file_error">파일 정보를 읽을 수 없습니다: %1$s</string>
<string name="detail_test_title">테스트: 원한다면 제목을 설정할 수 있습니다.</string>
<string name="detail_instant_delivery_disabled">즉시 전달 꺼짐</string>
<string name="detail_item_menu_save_file">파일 저장</string>
<string name="detail_item_download_failed">첨부 파일을 다운로드할 수 없습니다: %1$s</string>
<string name="detail_item_download_info_not_downloaded">다운로드되지 않음</string>
<string name="detail_item_download_info_not_downloaded_expired">다운로드되지 않음, 링크 만료됨</string>
<string name="detail_item_download_info_not_downloaded_expires_x">다운로드되지 않음, %1$s에 만료됨</string>
<string name="detail_item_download_info_deleted">삭제됨</string>
<string name="detail_item_download_info_download_failed">다운로드 실패</string>
<string name="detail_menu_notifications_enabled">알림 켜짐</string>
<string name="detail_menu_test">시험용 알림 발송</string>
<string name="detail_menu_settings">구독 설정</string>
<string name="detail_item_menu_copy_contents">알림 복사</string>
<string name="detail_item_saved_successfully">\"Downloads\" 폴더에 \"%1$s\"로 저장됨</string>
<string name="detail_item_cannot_open_url">URL을 열 수 없습니다: %1$s</string>
<string name="detail_item_download_info_downloading_x_percent">%1$d%% 다운로드됨</string>
<string name="detail_action_mode_menu_copy">복사</string>
<string name="detail_action_mode_menu_delete">삭제</string>
<string name="detail_action_mode_delete_dialog_permanently_delete">영구 삭제</string>
<string name="share_topic_title">공유하기</string>
<string name="settings_notifications_auto_delete_summary_one_month">알림을 1달 뒤 자동으로 삭제함</string>
<string name="settings_general_users_summary">보호된 주제를 위한 사용자 추가/삭제</string>
<string name="detail_item_download_info_download_failed_expired">다운로드 실패, 링크 만료됨</string>
<string name="detail_item_download_info_deleted_expired">삭제됨, 링크 만료됨</string>
<string name="detail_item_download_info_deleted_expires_x">삭제됨, 링크 %1$s에 만료됨</string>
<string name="detail_item_download_info_download_failed_expires_x">다운로드 실패, 링크 %1$s에 만료됨</string>
<string name="detail_menu_notifications_disabled_forever">알림 음소거됨</string>
<string name="detail_menu_notifications_disabled_until">%1$s까지 알림 음소거됨</string>
<string name="detail_menu_copy_url">주제 주소 복사</string>
<string name="detail_menu_unsubscribe">구독 해제</string>
<string name="detail_action_mode_delete_dialog_message">선택한 알림을 영원히 삭제하시겠습니까\?</string>
<string name="detail_action_mode_delete_dialog_cancel">취소</string>
<string name="detail_settings_title">구독 설정</string>
<string name="share_title">공유</string>
<string name="share_content_image_error">이미지를 읽을 수 없습니다: %1$s</string>
<string name="share_content_file_text">파일이 공유됨</string>
<string name="share_suggested_topics">주제 추천</string>
<string name="notification_dialog_1h">1시간 후</string>
<string name="notification_dialog_2h">2시간 후</string>
<string name="notification_dialog_8h">8시간 후</string>
<string name="notification_dialog_forever">해제시</string>
<string name="notification_dialog_save">저장</string>
<string name="notification_dialog_enabled_toast_message">알림 음소거 해제됨</string>
<string name="notification_dialog_tomorrow">내일</string>
<string name="settings_general_users_prefs_user_used_by_many">주제 %1$s에서 사용됨</string>
<string name="settings_backup_restore_backup_entry_settings_only">설정만</string>
<string name="settings_advanced_broadcast_summary_enabled">앱이 들어오는 알림을 브로드캐스트할 수 있습니다</string>
<string name="settings_advanced_export_logs_title">로그 복사/업로드</string>
<string name="notification_dialog_muted_until_toast_message">알림 %1$s까지 음소거됨</string>
<string name="notification_dialog_30min">30분 후</string>
<string name="settings_notifications_auto_download_50m">50MB보다 작다면</string>
<string name="settings_notifications_auto_delete_summary_never">알림을 자동으로 삭제하지 않음</string>
<string name="settings_general_users_prefs_user_not_used">어떤 주제에서도 사용되지 않음</string>
<string name="settings_general_users_prefs_user_add_title">새 사용자 추가</string>
<string name="settings_backup_restore_backup_entry_everything_no_users">사용자 제외 모두</string>
<string name="settings_general_default_base_url_message">새 주제를 구독하거나 공유할 때 사용할 서버의 루트 URL을 입력하십시오.</string>
<string name="settings_general_users_title">사용자 관리</string>
<string name="settings_general_users_prefs_user_add">사용자 추가</string>
<string name="settings_general_users_prefs_user_add_summary">새 서버를 위한 사용자 추가</string>
<string name="settings_general_users_prefs_title">사용자</string>
<string name="settings_backup_restore_backup_successful">백업 생성됨</string>
<string name="settings_advanced_broadcast_title">메세지 브로드캐스트</string>
<string name="settings_advanced_record_logs_summary_enabled">장치에 로그(최대 1000줄) 기록 …</string>
<string name="settings_advanced_record_logs_summary_disabled">나중에 문제 보고를 위해 로그를 기록합니다.</string>
<string name="settings_advanced_export_logs_entry_upload_scrubbed">업로드 후 링크 복사 (검열본)</string>
<string name="settings_backup_restore_backup_failed">백업 실패: %1$s</string>
<string name="settings_backup_restore_restore_title">파일에서 복원</string>
<string name="settings_advanced_export_logs_entry_upload_original">업로드 후 링크 복사</string>
<string name="settings_advanced_export_logs_copied_logs">로그가 클립보드에 복사됨</string>
<string name="settings_advanced_export_logs_uploading">로그 업로드중 …</string>
<string name="settings_advanced_export_logs_error_uploading">로그를 업로드할 수 없음: %1$s</string>
<string name="settings_advanced_export_logs_scrub_dialog_text">여기 적힌 주제/서버 이름은 과일 이름으로 변경되었으므로 로그를 안전하게 공유할 수 있습니다:
\n
\n%1$s
\n
\n비밀번호도 가려졌지만 이곳에 표시되지 않았습니다.</string>
<string name="settings_advanced_export_logs_scrub_dialog_button_ok">확인</string>
<string name="settings_advanced_clear_logs_title">로그 초기화</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">JSON stream over HTTP로 연결합니다. 이 방식은 안정적이지만 배터리를 더 많이 사용합니다.</string>
<string name="settings_advanced_connection_protocol_entry_ws">웹소켓</string>
<string name="settings_about_header">정보</string>
<string name="detail_settings_notifications_instant_title">즉시 전달</string>
<string name="settings_advanced_connection_protocol_summary_ws">웹소켓을 사용해 서버에 연결합니다. 권장되는 방식이지만 서버 프록시에 추가 설정이 필요할 수 있습니다.</string>
<string name="settings_advanced_clear_logs_summary">기존 로그를 모두 지우고 새로 시작</string>
<string name="settings_about_version_title">버전</string>
<string name="settings_about_version_format">ntfy %1$s (%2$s)</string>
<string name="detail_settings_notifications_instant_summary_on">알림이 즉시 전달됩니다. 서비스가 항시 실행되어야 하며 배터리 소모가 많습니다.</string>
<string name="detail_settings_notifications_instant_summary_off">알림이 Firebase를 통해 전달됩니다. 약간의 지연이 발생할 수 있으나 배터리 소모가 적습니다.</string>
<string name="detail_settings_appearance_icon_set_title">구독 아이콘</string>
<string name="detail_settings_appearance_icon_remove_title">구독 아이콘 (터치해서 제거)</string>
<string name="detail_settings_appearance_icon_remove_summary">이 주제의 알림에 표시될 아이콘</string>
<string name="detail_settings_appearance_display_name_message">이 구독을 표시할 이름을 지정합니다. 빈 값을 지정하면 기본 이름(%1$s)이 사용됩니다.</string>
<string name="detail_settings_appearance_display_name_default_summary">%1$s (기본)</string>
<string name="detail_settings_about_header">정보</string>
<string name="detail_settings_appearance_icon_set_summary">알림에 표시될 아이콘을 지정합니다</string>
<string name="detail_settings_appearance_icon_error_saving">아이콘을 저장할 수 없습니다: %1$s</string>
<string name="detail_settings_global_setting_suffix">전역 설정 사용중</string>
<string name="user_dialog_description_add">여기에서 사용자를 추가할 수 있습니다. 지정한 서버의 모든 주제는 이 로그인 정보를 사용합니다.</string>
<string name="user_dialog_username_hint">사용자 이름</string>
<string name="user_dialog_button_cancel">취소</string>
<string name="detail_settings_appearance_display_name_title">표시 이름</string>
<string name="detail_settings_about_topic_url_title">주제 URL</string>
<string name="user_dialog_title_edit">사용자 편집</string>
<string name="user_dialog_base_url_hint">서비스 URL</string>
<string name="user_dialog_password_hint_edit">비밀번호 (변경시에만 입력)</string>
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">클립보드에 복사됨</string>
<string name="user_dialog_title_add">사용자 추가</string>
<string name="user_dialog_description_edit">선택한 사용자의 아이디나 비밀번호를 변경하거나 삭제할 수 있습니다.</string>
<string name="user_dialog_password_hint_add">비밀번호</string>
<string name="user_dialog_button_add">사용자 추가</string>
<string name="user_dialog_button_delete">사용자 삭제</string>
</resources>

View file

@ -1,77 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="add_dialog_login_new_user">Ny bruker</string>
<string name="channel_notifications_low_name">Lav prioritet</string>
<string name="channel_notifications_default_name">Standard prioritet</string>
<string name="channel_notifications_low_name">Merknader (lav prioritet)</string>
<string name="channel_notifications_default_name">Merknader (forvalgt prioritet)</string>
<string name="channel_subscriber_service_name">Abonnementstjeneste</string>
<string name="channel_subscriber_notification_title">Lytter etter innkommende varsler</string>
<string name="channel_subscriber_notification_instant_text">Abonnert på emner med umiddelbar levering</string>
<string name="channel_subscriber_notification_instant_text_one">Abonnert på ett emne med umiddelbar levering</string>
<string name="channel_subscriber_notification_instant_text_four">Abonnert på fire emner med umiddelbar levering</string>
<string name="channel_subscriber_notification_instant_text_more">Abonnert på %1$d emner med umiddelbar levering</string>
<string name="channel_subscriber_notification_noinstant_text_one">Abonnert på ett emne</string>
<string name="channel_subscriber_notification_noinstant_text_two">Abonnert på to emner</string>
<string name="channel_subscriber_notification_noinstant_text">Abonnert på emner</string>
<string name="channel_subscriber_notification_noinstant_text_three">Abonnert på tre emner</string>
<string name="channel_subscriber_notification_noinstant_text_four">Abonnert på fire emner</string>
<string name="refresh_message_result">%1$d varsling(er) mottatt</string>
<string name="channel_notifications_max_name">Maks prioritet</string>
<string name="refresh_message_error_one">Kunne ikke oppdatere abonnement: %1$s</string>
<string name="main_menu_notifications_enabled">Varsler påslått</string>
<string name="main_menu_notifications_disabled_forever">Varsler dempet</string>
<string name="channel_subscriber_notification_title">Lytter etter innkommende merknader</string>
<string name="channel_subscriber_notification_instant_text">Du abonnerer på emner med umiddelbar levering</string>
<string name="channel_subscriber_notification_instant_text_one">Du abonnerer på ett emne med umiddelbar levering</string>
<string name="channel_subscriber_notification_instant_text_four">Du abonnerer på fire emner med umiddelbar levering</string>
<string name="channel_subscriber_notification_instant_text_more">Du abonnerer på %1$d emner med umiddelbar levering</string>
<string name="channel_subscriber_notification_noinstant_text_one">Du abonnerer på ett emne</string>
<string name="channel_subscriber_notification_noinstant_text_two">Du abonnerer på to emner</string>
<string name="channel_subscriber_notification_noinstant_text">Du abonnerer på emner</string>
<string name="channel_subscriber_notification_noinstant_text_three">Du abonnerer på tre emner</string>
<string name="channel_subscriber_notification_noinstant_text_four">Du abonnerer på fire emner</string>
<string name="refresh_message_result">%1$d merknad(er) mottatt</string>
<string name="channel_notifications_max_name">Merknader (maks.-prioritet)</string>
<string name="refresh_message_error_one">Kunne ikke gjenoppfriske abonnementet: %1$s</string>
<string name="main_menu_notifications_enabled">Merknader påslått</string>
<string name="main_menu_notifications_disabled_forever">Merknader avslått</string>
<string name="main_menu_docs_title">Les dokumentasjonen</string>
<string name="main_menu_rate_title">Vurder appen</string>
<string name="main_action_mode_menu_unsubscribe">Avslutt abonnement</string>
<string name="main_menu_rate_title">Vurder programmet</string>
<string name="main_action_mode_menu_unsubscribe">Opphev abonnement</string>
<string name="main_action_mode_delete_dialog_permanently_delete">Slett for godt</string>
<string name="main_action_mode_delete_dialog_cancel">Avbryt</string>
<string name="main_item_status_text_one">%1$d varsling</string>
<string name="main_item_status_text_not_one">%1$d varsler</string>
<string name="main_item_status_reconnecting">kobler til på nytt</string>
<string name="main_item_status_text_one">%1$d merknad</string>
<string name="main_item_status_text_not_one">%1$d merknader</string>
<string name="main_item_status_reconnecting">kobler til igjen</string>
<string name="main_item_date_yesterday">i går</string>
<string name="main_add_button_description">Legg til abonnement</string>
<string name="main_banner_websocket_button_remind_later">Spør senere</string>
<string name="main_banner_json_stream_button_remind_later">Spør senere</string>
<string name="main_banner_json_stream_button_learn_more">Lær mer</string>
<string name="add_dialog_title">Abonner på emnet</string>
<string name="add_dialog_topic_name_hint">Emnenavn, f.eks. halgeirs_varsler</string>
<string name="add_dialog_use_another_server">Bruk en annen tjener</string>
<string name="add_dialog_instant_delivery">Umiddelbar varsling i slumremodus</string>
<string name="main_banner_battery_button_remind_later">Spør senere</string>
<string name="main_banner_battery_button_fix_now">Fiks nå</string>
<string name="main_action_mode_delete_dialog_message">Avslutt abonnementet på de valgte emnene og slett alle varsler permanent\?</string>
<string name="main_no_subscriptions_text">Det ser ut til at du ikke har noen abonnementer ennå.</string>
<string name="main_banner_battery_text">Batterioptimalisering bør være av for å unngå problemer med varsellevering.</string>
<string name="main_action_mode_delete_dialog_message">Opphev abonnement på valgte emne(r) og slett alle merknader du har mottatt for godt\?</string>
<string name="main_no_subscriptions_text">Abonner på noe først</string>
<string name="main_banner_battery_text">Batterioptimalisering bør skrus av for å unngå problemer med merknadsleveringen.</string>
<string name="main_banner_battery_button_dismiss">Avfei</string>
<string name="main_banner_websocket_button_dismiss">Avfei</string>
<string name="add_dialog_description_below">Emner er kanskje ikke passordbeskyttet, så velg et navn som er vanskelig å gjette. Når du har abonnert, kan du sende PUT/POST-varsler.</string>
<string name="add_dialog_use_another_server_description">Skriv inn tjeneste-URLer nedenfor for å abonnere på emner fra andre servere.</string>
<string name="main_banner_json_stream_button_dismiss">Avfei</string>
<string name="add_dialog_description_below">Det kan hende emner ikke er passordsbeskyttet, så velg et navn som ikke er enkelt å gjette. Når du har abonnert kan du utføre PUT/POST av merknader.</string>
<string name="add_dialog_use_another_server_description">Du kan abonnere på emner fra en annen tjener. Skriv inn tjener-nettadressen nedenfor.</string>
<string name="main_item_status_unified_push">%1$s (UnifiedPush)</string>
<string name="add_dialog_button_login">Logg inn</string>
<string name="add_dialog_error_connection_failed">Tilkobling mislyktes: %1$s</string>
<string name="add_dialog_login_username_hint">Brukernavn</string>
<string name="add_dialog_login_password_hint">Passord</string>
<string name="add_dialog_login_error_not_authorized">Innlogging mislyktes. Bruker %1$s har ikke tilgang.</string>
<string name="add_dialog_login_error_not_authorized">Innlogging mislyktes. Brukeren %1$s er ikke identitetsbekreftet.</string>
<string name="detail_no_notifications_text">Du har ikke mottatt noen merknader om dette emnet enda.</string>
<string name="detail_clear_dialog_message">Slett alle varsler i dette emnet\?</string>
<string name="detail_clear_dialog_message">Slett alle andre merknader i emnet\?</string>
<string name="detail_delete_dialog_permanently_delete">Slett for godt</string>
<string name="detail_delete_dialog_cancel">Avbryt</string>
<string name="detail_test_title">Test: Du kan sette en tittel hvis du vil.</string>
<string name="detail_test_title">Test: Du kan sette en tittel hvis du vil</string>
<string name="detail_test_message_error">Kan ikke sende melding: %1$s</string>
<string name="detail_how_to_link">Detaljerte instruksjoner er tilgjengelig på ntfy.sh, og i dokumentasjonen.</string>
<string name="detail_how_to_link">Mer detaljert instruks er å finne på ntfy.sh-nettsiden og i dokumentasjonen.</string>
<string name="detail_delete_dialog_message">Opphev abonnement på dette emnet og slett alle merknader du har mottatt\?</string>
<string name="detail_test_message_error_unauthorized_anon">Kan ikke sende melding: Anonym publisering er ikke tillatt.</string>
<string name="detail_test_message_error_unauthorized_anon">Kan ikke sende melding: Anonym publisering tillates ikke</string>
<string name="add_dialog_instant_delivery_description">Forsikrer at meldinger blir levert umiddelbart, selv når enheten er inaktiv.</string>
<string name="add_dialog_login_description">Dette emnet krever at du logger inn. Skriv inn et brukernavn og passord.</string>
<string name="detail_how_to_intro">For å sende merknader til dette emnet kan du utføre PUT eller POST til emne-nettadressen.</string>
<string name="detail_how_to_example">Eksempel (ved bruk av curl):<br/><tt>$ curl -d \"Hei\" %1$s</tt></string>
<string name="detail_how_to_example">Eksempel (ved bruk av Curl):<br/><tt>$ curl -d «Hei» %1$s</tt></string>
<string name="detail_item_snack_deleted">Merknad slettet</string>
<string name="detail_item_menu_cancel">Avbryt nedlasting</string>
<string name="detail_item_menu_save_file">Lagre fil</string>
<string name="detail_item_menu_copy_url">Kopier nettadresse</string>
<string name="detail_item_menu_copy_url_copied">URL kopiert til utklippstavlen</string>
<string name="detail_item_menu_copy_url_copied">Nettadresse kopiert til utklippstavlen</string>
<string name="detail_item_menu_copy_contents">Kopier merknad</string>
<string name="detail_item_cannot_download">Kan ikke åpne eller laste ned vedlegg. Lenken utløp og ingen lokal fil ble funnet.</string>
<string name="detail_item_cannot_open">Kan ikke åpne vedlegg: %1$s</string>
<string name="detail_item_cannot_open_not_found">Kan ikke åpne vedlegg: Filen kan ha blitt slettet, eller ingen installerte apper kan åpne filen.</string>
<string name="detail_item_cannot_open_url">Kan ikke åpne klikkbar nettadresse: %1$s</string>
<string name="detail_item_cannot_open_not_found">Kan ikke åpne vedlegg: Filen kan ha blitt slettet, eller så mangler det et program til å åpne filen.</string>
<string name="detail_item_cannot_open_click_url">Kan ikke åpne klikkbar nettadresse: %1$s</string>
<string name="detail_item_cannot_delete">Kan ikke slette vedlegg: %1$s</string>
<string name="detail_item_download_info_not_downloaded">ikke nedlastet</string>
<string name="detail_item_download_info_downloading_x_percent">%1$d%% nedlastet</string>
@ -81,8 +82,8 @@
<string name="detail_item_download_info_download_failed">nedlasting mislyktes</string>
<string name="detail_item_download_info_download_failed_expired">nedlasting mislyktes, utløpt lenke</string>
<string name="detail_item_download_info_download_failed_expires_x">nedlasting mislyktes, lenke utløper %1$s</string>
<string name="detail_menu_notifications_enabled">Varsler på</string>
<string name="detail_menu_notifications_disabled_forever">Varsler dempet</string>
<string name="detail_menu_notifications_enabled">Merknader påslått</string>
<string name="detail_menu_notifications_disabled_forever">Merknader avslått</string>
<string name="detail_menu_enable_instant">Skru på umiddelbar levering</string>
<string name="detail_menu_disable_instant">Skru av umiddelbar levering</string>
<string name="detail_menu_test">Send testmerknad</string>
@ -91,17 +92,17 @@
<string name="detail_menu_settings">Abonnementsinnstillinger</string>
<string name="detail_menu_unsubscribe">Opphev abonnement</string>
<string name="detail_instant_delivery_disabled">Umiddelbar levering avskrudd</string>
<string name="detail_item_menu_copy_contents_copied">Varsel kopiert til utklippstavlen</string>
<string name="detail_test_message_error_unauthorized_user">Kan ikke sende melding: Brukeren \"%1$s\" er ikke autorisert.</string>
<string name="detail_test_message_error_too_large">Kan ikke sende melding: Vedlegget er for stort.</string>
<string name="detail_item_menu_copy_contents_copied">Merknad kopiert til utklippstavlen</string>
<string name="detail_test_message_error_unauthorized_user">Kan ikke sende melding: Brukeren «%1$s» er ikke identitetsbekreftet</string>
<string name="detail_test_message_error_too_large">Kan ikke sende melding: Vedlegget er for stort</string>
<string name="detail_copied_to_clipboard_message">Kopiert til utklippstavlen</string>
<string name="detail_instant_delivery_enabled">Umiddelbar levering påskrudd</string>
<string name="detail_action_mode_delete_dialog_permanently_delete">Slett permanent</string>
<string name="detail_action_mode_delete_dialog_permanently_delete">Slett for godt</string>
<string name="detail_action_mode_delete_dialog_cancel">Avbryt</string>
<string name="share_title">Del</string>
<string name="share_menu_send">Del</string>
<string name="share_content_title">Meldingsforhåndsvisning</string>
<string name="share_content_text_hint">Legg til innhold for å dele her</string>
<string name="share_content_text_hint">Legg innhold du ønsker å dele her</string>
<string name="share_content_image_text">Et bilde ble delt med deg</string>
<string name="share_content_file_text">En fil ble delt med deg</string>
<string name="share_topic_title">Del til</string>
@ -112,33 +113,33 @@
<string name="notification_dialog_2h">2 timer</string>
<string name="notification_dialog_8h">8 timer</string>
<string name="notification_dialog_tomorrow">Til i morgen</string>
<string name="notification_dialog_forever">Inntil gjenopptatt</string>
<string name="notification_dialog_forever">Til de blir slått på igjen</string>
<string name="notification_popup_action_open">Åpne</string>
<string name="settings_title">Innstillinger</string>
<string name="settings_notifications_header">Merknader</string>
<string name="settings_notifications_muted_until_title">Skru av varsler</string>
<string name="settings_notifications_muted_until_show_all">Viser alle varsler</string>
<string name="settings_notifications_muted_until_forever">Varsler er dempet til de gjenopptas</string>
<string name="settings_notifications_muted_until_x">Varsler avslått til %1$s</string>
<string name="settings_notifications_muted_until_title">Sett merknader på pause</string>
<string name="settings_notifications_muted_until_show_all">Alle merknader vil bli vist</string>
<string name="settings_notifications_muted_until_forever">Merknader forstummet til de blir skrudd på igjen</string>
<string name="settings_notifications_muted_until_x">Merknader forstummet til %1$s</string>
<string name="settings_notifications_min_priority_min">Alle prioriteter</string>
<string name="settings_notifications_min_priority_summary_max">Vis varsler hvis prioritet er 5 (maks.)</string>
<string name="settings_notifications_min_priority_default">Standardprioritet og over</string>
<string name="settings_notifications_min_priority_summary_max">Vis merknader hvis prioritet er 5 (maks.)</string>
<string name="settings_notifications_min_priority_default">Forvalgt prioritet</string>
<string name="settings_notifications_min_priority_low">Lav prioritet og høyere</string>
<string name="settings_notifications_min_priority_high">Høy prioritet og over</string>
<string name="settings_notifications_min_priority_high">Høy prioritet og høyere</string>
<string name="settings_notifications_min_priority_max">Kun maks.-prioritet</string>
<string name="settings_notifications_auto_download_title">Last ned vedlegg</string>
<string name="settings_notifications_auto_download_summary_always">Last ned alle vedlegg automatisk</string>
<string name="settings_notifications_auto_download_summary_never">Last aldri ned vedlegg automatisk</string>
<string name="settings_notifications_auto_download_summary_never">Aldri last ned vedlegg automatisk</string>
<string name="settings_notifications_auto_download_summary_smaller_than_x">Last ned vedlegg opptil %1$s automatisk</string>
<string name="settings_notifications_auto_download_never">Aldri last ned noe automatisk</string>
<string name="settings_notifications_auto_download_never">Aldri last ned automatisk</string>
<string name="settings_notifications_auto_download_always">Alltid last ned automatisk</string>
<string name="settings_notifications_auto_download_100k">Hvis under 100 kB</string>
<string name="settings_notifications_auto_download_1m">Hvis under 1 MB</string>
<string name="settings_notifications_auto_download_5m">Hvis under 5 MB</string>
<string name="settings_notifications_auto_download_10m">Hvis under 10 MB</string>
<string name="settings_notifications_min_priority_summary_any">Viser alle varsler</string>
<string name="settings_notifications_min_priority_summary_x_or_higher">Vis varsler hvis prioritet er %1$d (%2$s) eller høyere</string>
<string name="settings_notifications_auto_delete_summary_never">Slett aldri varsler automatisk</string>
<string name="settings_notifications_auto_download_100k">Hvis mindre enn 100 KB</string>
<string name="settings_notifications_auto_download_1m">Hvis mindre enn 1 MB</string>
<string name="settings_notifications_auto_download_5m">Hvis mindre enn 5 MB</string>
<string name="settings_notifications_auto_download_10m">Hvis mindre enn 10 MB</string>
<string name="settings_notifications_min_priority_summary_any">Merknader av alle prioriteter vises</string>
<string name="settings_notifications_min_priority_summary_x_or_higher">Vis merknader hvis prioritet er %1$d (%2$s) eller høyere</string>
<string name="settings_notifications_auto_delete_summary_never">Aldri slett merknader automatisk</string>
<string name="settings_notifications_auto_delete_one_week">Etter én uke</string>
<string name="settings_notifications_auto_delete_summary_one_month">Slett merknader automatisk etter én måned</string>
<string name="settings_notifications_auto_delete_one_month">Etter én måned</string>
@ -149,37 +150,37 @@
<string name="settings_general_users_summary">Legg til/fjern brukere for beskyttede emner</string>
<string name="settings_general_users_prefs_title">Brukere</string>
<string name="settings_general_users_prefs_user_not_used">Ikke brukt av noen emner</string>
<string name="settings_general_users_prefs_user_used_by_one">Brukt av emnet \"%1$s\"</string>
<string name="settings_general_users_prefs_user_used_by_many">Brukt av emnene %1$s</string>
<string name="settings_general_users_prefs_user_used_by_one">Brukt av emnet «%1$s»</string>
<string name="settings_general_users_prefs_user_used_by_many">Brukt av emnene «%1$s»</string>
<string name="settings_general_users_prefs_user_add">Legg til brukere</string>
<string name="settings_general_users_prefs_user_add_title">Legg til ny bruker</string>
<string name="settings_general_users_prefs_user_add_summary">Opprett en ny bruker for en ny tjener</string>
<string name="settings_general_dark_mode_title">Mørk drakt</string>
<string name="settings_general_dark_mode_summary_system">Bruker systemets standard</string>
<string name="settings_general_dark_mode_summary_light">Lys modus på</string>
<string name="settings_general_dark_mode_summary_dark">Mørk modus på. Er du en vampyr\?</string>
<string name="settings_general_dark_mode_summary_system">Ikled systemets drakt</string>
<string name="settings_general_dark_mode_summary_light">Lys drakt iført</string>
<string name="settings_general_dark_mode_summary_dark">Mørk dra iført. Er du en mørkets fyrste\?</string>
<string name="settings_general_dark_mode_entry_system">Bruk systemets forvalg</string>
<string name="settings_general_dark_mode_entry_light">Lys drakt</string>
<string name="settings_general_dark_mode_entry_dark">Mørk drakt</string>
<string name="settings_backup_restore_header">Sikkerhetskopiering og gjenoppretting</string>
<string name="settings_notifications_auto_delete_summary_one_day">Slett merknader automatisk etter én dag</string>
<string name="settings_general_default_base_url_message">Skriv inn serverens rot-URL for å bruke din egen server som standard når du abonnerer på nye emner og/eller deler til emner.</string>
<string name="settings_general_default_base_url_message">For å bruke din egen tjener som forvalg når du abonnerer på nye emner og/eller deler til emner, kan du skrive inn tjenerens grunn-nettadresse.</string>
<string name="settings_backup_restore_restore_title">Gjenopprett fra fil</string>
<string name="settings_advanced_header">Avansert</string>
<string name="settings_advanced_export_logs_entry_copy_scrubbed">Kopier til utklippstavlen (sensurert)</string>
<string name="settings_advanced_export_logs_entry_upload_scrubbed">Last opp og kopier lenke (sensurert)</string>
<string name="settings_advanced_export_logs_copied_logs">Loggføring kopiert til utklippstavlen</string>
<string name="settings_advanced_export_logs_uploading">Laster opp logg …</string>
<string name="settings_advanced_export_logs_copied_url">Logger lastet opp og URL kopiert</string>
<string name="settings_backup_restore_backup_title">Sikkerhetskopier til fil</string>
<string name="settings_backup_restore_backup_summary">Eksporter konfigurasjon, varsler og brukere</string>
<string name="settings_advanced_export_logs_copied_url">Loggføring opplastet og nettadresse kopiert</string>
<string name="settings_backup_restore_backup_title">Sikkerhetskopiering til fil</string>
<string name="settings_backup_restore_backup_summary">Eksporter oppsett, merknader og brukere</string>
<string name="settings_backup_restore_backup_entry_everything">Alt</string>
<string name="settings_backup_restore_backup_entry_everything_no_users">Alt, unntatt brukere</string>
<string name="settings_advanced_broadcast_summary_enabled">Programmer kan motta innkommende merknader som kringkastinger</string>
<string name="settings_advanced_broadcast_summary_disabled">Programmer kan motta merknader som kringkastinger</string>
<string name="settings_advanced_record_logs_title">Registrer logger</string>
<string name="settings_advanced_record_logs_summary_enabled">Logger (opptil 1000 oppføringer) til enheten …</string>
<string name="settings_advanced_record_logs_summary_disabled">Slå på logging, slik at du kan dele logger senere for å diagnostisere problemer.</string>
<string name="settings_advanced_record_logs_title">Loggføring</string>
<string name="settings_advanced_record_logs_summary_enabled">Logger blir registrert på enheten din. Opptil 1000 oppføringer lagres.</string>
<string name="settings_advanced_record_logs_summary_disabled">Skru på registrering av logger, slik at du kan dele dem senere. Dette er nyttig i avlusingsøyemed.</string>
<string name="settings_advanced_export_logs_title">Kopier/last opp logger</string>
<string name="settings_advanced_export_logs_entry_copy_original">Kopier til utklippstavlen</string>
<string name="settings_advanced_export_logs_error_uploading">Kunne ikke laste opp logger: %1$s</string>
@ -188,43 +189,43 @@
\n
\n%1$s
\n
\nPassord er fjernet, men er ikke opplistet her.</string>
\nPassord vil alltid fjernes, men er ikke opplistet her.</string>
<string name="settings_advanced_export_logs_scrub_dialog_empty">Ingen emner/vertsnavn ble fjernet. Kanskje du ikke har noen abonnementer\?</string>
<string name="settings_advanced_export_logs_scrub_dialog_button_ok">OK</string>
<string name="settings_advanced_export_logs_scrub_dialog_button_ok">Skjønner</string>
<string name="settings_advanced_clear_logs_title">Tøm loggføring</string>
<string name="settings_advanced_clear_logs_summary">Slett tidligere registrert loggføring, og start på ny</string>
<string name="settings_advanced_clear_logs_deleted_toast">Logger slettet</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Bruk en JSON-strøm over HTTP for å koble til tjeneren. Dette er en godt utprøvd metode, men kan bruke mer batteri.</string>
<string name="settings_advanced_clear_logs_deleted_toast">Loggføring slettet</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Bruk en JSON-strøm over HTTP for å koble til tjeneren. Dette er en godt utprøvd metode, selv om den kan bruke mer batteri.</string>
<string name="settings_about_header">Om</string>
<string name="settings_about_version_copied_to_clipboard_message">Kopiert til utklippstavlen</string>
<string name="user_dialog_title_add">Legg til bruker</string>
<string name="user_dialog_title_edit">Rediger bruker</string>
<string name="user_dialog_base_url_hint">Tjeneste-URL</string>
<string name="user_dialog_base_url_hint">Tjener-nettadresse</string>
<string name="user_dialog_description_edit">Du kan redigere brukernavn/passord for valgt bruker, eller slette den helt.</string>
<string name="settings_advanced_connection_protocol_entry_jsonhttp">JSON-strøm over HTTP</string>
<string name="settings_advanced_connection_protocol_entry_ws">Vev-sockets</string>
<string name="user_dialog_description_add">Du kan legge til en bruker her. Alle emner for den gitte serveren vil bruke denne brukeren.</string>
<string name="settings_about_version_format">ntfy %1$s (%2$s)</string>
<string name="user_dialog_description_add">Du kan legge til en bruker her som du kan tilknytte et gitt emne senere.</string>
<string name="settings_about_version_format">Ntfy %1$s (%2$s)</string>
<string name="user_dialog_password_hint_edit">Passord (uendret hvis tomt)</string>
<string name="user_dialog_button_add">Legg til bruker</string>
<string name="user_dialog_button_cancel">Avbryt</string>
<string name="user_dialog_button_delete">Slett bruker</string>
<string name="user_dialog_button_save">Lagre</string>
<string name="channel_subscriber_notification_instant_text_three">Abonnert på tre emner med umiddelbar levering</string>
<string name="channel_subscriber_notification_noinstant_text_more">Abonnert på %1$d emner</string>
<string name="channel_subscriber_notification_instant_text_three">Du abonnerer på tre emner med umiddelbar levering</string>
<string name="channel_subscriber_notification_noinstant_text_more">Du abonnerer på %1$d emner</string>
<string name="main_menu_settings_title">Innstillinger</string>
<string name="channel_notifications_min_name">Minste prioritet</string>
<string name="channel_notifications_high_name">Høy prioritet</string>
<string name="channel_subscriber_notification_instant_text_two">Abonnert på to emner med umiddelbar levering</string>
<string name="refresh_message_error">Kunne ikke oppdatere %1$d abonnement(er)
<string name="channel_notifications_min_name">Merknader (min.-prioritet)</string>
<string name="channel_notifications_high_name">Merknader (høy prioritet)</string>
<string name="channel_subscriber_notification_instant_text_two">Du abonnerer på to emner med umiddelbar levering</string>
<string name="refresh_message_error">Kunne ikke gjenoppfriske %1$d abonnement(er)
\n
\n%2$s</string>
<string name="add_dialog_button_back">Tilbake</string>
<string name="refresh_message_no_results">Alt er oppdatert</string>
<string name="refresh_message_no_results">Alt er av nyeste dato</string>
<string name="main_action_bar_title">Abonnerte emner</string>
<string name="main_menu_notifications_disabled_until">Varsler dempet til %1$s</string>
<string name="add_dialog_login_title">Innlogging nødvendig</string>
<string name="main_menu_report_bug_title">Rapporter en feil</string>
<string name="main_menu_notifications_disabled_until">Merknader avslått til %1$s</string>
<string name="add_dialog_login_title">Innlogging kreves</string>
<string name="main_menu_report_bug_title">Innrapporter en feil</string>
<string name="add_dialog_button_subscribe">Abonner</string>
<string name="detail_clear_dialog_permanently_delete">Slett for godt</string>
<string name="detail_item_tags">Etiketter: %1$s</string>
@ -234,10 +235,10 @@
<string name="detail_item_menu_delete">Slett fil</string>
<string name="detail_item_menu_download">Last ned fil</string>
<string name="detail_item_menu_open">Åpne fil</string>
<string name="detail_item_saved_successfully">Lagret som \"%1$s\" i nedlastingsmappen</string>
<string name="detail_item_saved_successfully">Lagret som «%1$s» i nedlastingsmappen</string>
<string name="detail_item_download_info_not_downloaded_expired">ikke nedlastet, utløpt lenke</string>
<string name="detail_item_download_info_not_downloaded_expires_x">ikke nedlastet, utløper %1$s</string>
<string name="detail_menu_notifications_disabled_until">Varsler avslått til %1$s</string>
<string name="detail_menu_notifications_disabled_until">Merknader avslått til %1$s</string>
<string name="detail_item_cannot_save">Kan ikke lagre vedlegg: %1$s</string>
<string name="detail_action_mode_menu_copy">Kopier</string>
<string name="notification_popup_action_cancel">Avbryt</string>
@ -245,9 +246,9 @@
\nFil: %2$s</string>
<string name="notification_popup_file_downloading">Laster ned %1$s, %2$d%%
\n%3$s</string>
<string name="detail_item_download_failed">Kunne ikke laste ned vedlegg: %1$s</string>
<string name="detail_item_download_failed">Nedlasting av vedlegg mislyktes: %1$s</string>
<string name="detail_action_mode_menu_delete">Slett</string>
<string name="detail_action_mode_delete_dialog_message">Vil du slette valgt(e) varsling(er) permanent\?</string>
<string name="detail_action_mode_delete_dialog_message">Slett valgt(e) merknad(er)\?</string>
<string name="detail_settings_title">Abonnementsinnstillinger</string>
<string name="share_suggested_topics">Foreslåtte emner</string>
<string name="share_successful">Melding publisert</string>
@ -256,27 +257,27 @@
<string name="notification_popup_file_download_successful">%1$s
\nFil: %2$s, nedlastet</string>
<string name="share_content_image_error">Kan ikke lese bilde: %1$s</string>
<string name="notification_dialog_enabled_toast_message">Varsler gjenopptatt</string>
<string name="notification_dialog_muted_until_toast_message">Varsler avslått til %1$s</string>
<string name="settings_notifications_min_priority_title">Minste prioritet</string>
<string name="share_content_file_error">Kan ikke lese filinformasjon: %1$s</string>
<string name="notification_dialog_title">Skru av varsler</string>
<string name="notification_dialog_muted_forever_toast_message">Varsler dempet</string>
<string name="notification_dialog_enabled_toast_message">Merknader skrudd på igjen</string>
<string name="notification_dialog_muted_until_toast_message">Merknader satt på pause til %1$s</string>
<string name="settings_notifications_min_priority_title">Min.-prioritet</string>
<string name="share_content_file_error">Kan ikke lese filinfo: %1$s</string>
<string name="notification_dialog_title">Sett merknader på pause</string>
<string name="notification_dialog_muted_forever_toast_message">Merknader satt på pause</string>
<string name="notification_dialog_1h">1 time</string>
<string name="notification_popup_file_download_failed">%1$s
\nFil: %2$s, nedlasting mislyktes</string>
<string name="user_dialog_username_hint">Brukernavn</string>
<string name="settings_notifications_auto_download_50m">Hvis under 50 MB</string>
<string name="settings_notifications_auto_download_50m">Hvis mindre enn 50 MB</string>
<string name="settings_notifications_auto_delete_title">Slett merknader</string>
<string name="settings_notifications_auto_download_500k">Hvis under 500 kB</string>
<string name="settings_notifications_auto_download_500k">Hvis mindre enn 500 KB</string>
<string name="settings_backup_restore_backup_failed">Sikkerhetskopiering mislyktes: %1$s</string>
<string name="settings_backup_restore_restore_successful">Gjenoppretting vellykket</string>
<string name="settings_backup_restore_restore_successful">Gjenopprettet</string>
<string name="user_dialog_password_hint_add">Passord</string>
<string name="settings_backup_restore_restore_failed">Gjenoppretting mislyktes: %1$s</string>
<string name="settings_advanced_export_logs_entry_upload_original">Last opp og kopier lenke</string>
<string name="settings_about_version_title">Versjon</string>
<string name="settings_advanced_broadcast_title">Kringkast meldinger</string>
<string name="settings_notifications_auto_delete_summary_three_days">Slett varsler automatisk etter tre dager</string>
<string name="settings_notifications_auto_delete_summary_three_days">Slett merknader automatisk etter tre dager</string>
<string name="settings_notifications_auto_delete_summary_three_months">Slett merknader automatisk etter tre måneder</string>
<string name="settings_notifications_auto_delete_one_day">Etter én dag</string>
<string name="settings_notifications_auto_delete_summary_one_week">Slett merknader automatisk etter én uke</string>
@ -285,62 +286,18 @@
<string name="settings_general_default_base_url_default_summary">%1$s (forvalg)</string>
<string name="settings_backup_restore_backup_entry_settings_only">Kun innstillinger</string>
<string name="settings_backup_restore_restore_summary">Importer oppsett, merknader og brukere</string>
<string name="detail_test_message">Dette er et testvarsel fra ntfy Android-appen. Den har en nivå %1$d prioritet. Hvis du sender en annen, kan den se annerledes ut.</string>
<string name="settings_backup_restore_backup_successful">Sikkerhetskopiering opprettet</string>
<string name="settings_advanced_export_logs_summary">Kopier logger til utklippstavlen, eller last opp til nopaste.net (eid av ntfy-utvikleren). Vertsnavn og emner kan sensureres, men varsler vil aldri bli det.</string>
<string name="settings_advanced_connection_protocol_summary_ws">Bruk WebSockets for å koble til serveren. Dette er den anbefalte metoden, men kan kreve ytterligere konfigurasjon i proxyen din.</string>
<string name="main_how_to_intro">Klikk på + for å opprette eller abonnere på et emne. Etterpå mottar du varsler på enheten din når du sender meldinger via PUT eller POST.</string>
<string name="main_how_to_link">Detaljerte instruksjoner er tilgjengelig på ntfy.sh, og i dokumentasjonen.</string>
<string name="detail_test_message">Dette er en testmerknad fra ntfy-Androidprogrammet. Det har %1$d-prioritet. vis du sender en ny kan det hende den ser annerledes ut.</string>
<string name="settings_backup_restore_backup_successful">Sikkerhetskopi utført</string>
<string name="settings_advanced_export_logs_summary">Kopier logger til utklippstavlen, eller last opp til nopaste.net (eid av ntfy-utvikleren). Vertsnavn og emner kan sensureres, men merknader vil aldri bli det.</string>
<string name="settings_advanced_connection_protocol_summary_ws">Bruk Vev-socket-er for å koble til tjeneren. Dette er eksperimentelt. Si ifra hvis det bruker mindre batteri eller er ustabilt.</string>
<string name="main_how_to_intro">Abonner på et emne ved å klikke på knappen nedenfor. Etter dette kan du sende meldinger via PUT eller POST, og du kan motta merknader på enheten din.</string>
<string name="main_how_to_link">Mer detaljert instruks er å finne på ntfy.sh-nettsiden og i dokumentasjonen.</string>
<string name="main_unified_push_toast">Dette abonnementet håndteres av %1$s via UnifiedPush</string>
<string name="add_dialog_foreground_description">Umiddelbar levering er alltid påskrudd for andre verter enn %1$s.</string>
<string name="main_banner_json_stream_text">Fra Juni 2022 vil Vev-socketer bli brukt til å kommunisere med ntfy-tjenerne. Forsikre deg om at du har satt opp din selvtjente tjener for å støtte det. For å sjekke om vev-socket-støtte fungerer, kan du skru det på i innstillingene under «Tilkoblingsprotokoll».</string>
<string name="settings_notifications_priority_min">min</string>
<string name="settings_notifications_priority_low">lav</string>
<string name="settings_notifications_priority_default">forvalg</string>
<string name="settings_notifications_priority_high">høy</string>
<string name="settings_notifications_priority_max">maks.</string>
<string name="channel_subscriber_notification_instant_text_six">Abonnert på seks emner med umiddelbar levering</string>
<string name="channel_subscriber_notification_instant_text_five">Abonnert på fem emner med umiddelbar levering</string>
<string name="channel_subscriber_notification_noinstant_text_five">Abonnert på fem emner</string>
<string name="channel_subscriber_notification_noinstant_text_six">Abonnert på seks emner</string>
<string name="channel_notifications_group_default_name">Standard</string>
<string name="add_dialog_base_urls_dropdown_choose">Velg tjenestens URL</string>
<string name="add_dialog_base_urls_dropdown_clear">Fjern tjeneste-URL</string>
<string name="settings_notifications_insistent_max_priority_title">Fortsett å varsle for høyeste prioritet</string>
<string name="settings_notifications_insistent_max_priority_summary_enabled">Varslinger med maksimal prioritet varsler kontinuerlig til de blir avvist</string>
<string name="settings_notifications_insistent_max_priority_summary_disabled">Maks prioriterte varsler varsles bare én gang</string>
<string name="detail_settings_notifications_instant_title">Umiddelbar levering</string>
<string name="detail_settings_notifications_instant_summary_on">Varsler leveres umiddelbart. Krever en forgrunnsservice og bruker mer batteri.</string>
<string name="detail_settings_notifications_instant_summary_off">Varsler leveres med Firebase. Leveringen kan bli forsinket, men bruker mindre batteri.</string>
<string name="detail_settings_notifications_dedicated_channels_title">Egendefinerte varslingsinnstillinger</string>
<string name="detail_settings_notifications_dedicated_channels_summary_on">Bruker egendefinerte innstillinger for dette abonnementet</string>
<string name="detail_settings_notifications_dedicated_channels_summary_off">Bruker standardinnstillinger (lyder, Ikke forstyrr-overstyring osv.)</string>
<string name="detail_settings_notifications_open_channels_title">Konfigurer varslingsinnstillinger</string>
<string name="detail_settings_notifications_open_channels_summary">Ikke forstyrr (DND) overstyring, lyder osv.</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_enabled">Fortsett å varsle</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_disabled">Varsle bare én gang</string>
<string name="detail_settings_appearance_icon_remove_summary">Ikon som vises i varsler for dette emnet</string>
<string name="detail_settings_appearance_icon_error_saving">Kan ikke lagre ikon: %1$s</string>
<string name="detail_settings_appearance_display_name_title">Visningsnavn</string>
<string name="detail_settings_appearance_display_name_default_summary">%1$s (standard)</string>
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">Kopier til utklippstavlen</string>
<string name="detail_settings_appearance_display_name_message">Angi et tilpasset visningsnavn for dette abonnementet. La stå tomt for standard (%1$s).</string>
<string name="main_menu_donate_title">Doner 💸</string>
<string name="main_banner_websocket_text">Å bytte til WebSockets er den anbefalte måten å koble til serveren på, og kan forbedre batterilevetiden, men kan kreve <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">ytterligere konfigurasjon i proxy-serveren</a>. Dette kan endres i innstillingene.</string>
<string name="main_banner_websocket_button_enable_now">Aktiver nå</string>
<string name="detail_deep_link_subscribed_toast_message">Abonnerte på emnet %1$s</string>
<string name="detail_settings_appearance_header">Utseende</string>
<string name="detail_settings_appearance_icon_set_summary">Angi et ikon som skal vises i varsler</string>
<string name="detail_settings_appearance_icon_set_title">Abonnement-ikon</string>
<string name="detail_settings_global_setting_title">Bruk globale innstillinger</string>
<string name="detail_settings_about_header">Om</string>
<string name="detail_settings_about_topic_url_title">Emne-URL</string>
<string name="notification_popup_user_action_failed">%1$s mislyktes: %2$s</string>
<string name="detail_item_cannot_open_apk">Apper kan ikke installeres lenger. Last ned via nettleseren i stedet. Se feilrapport #531 for detaljer.</string>
<string name="detail_settings_appearance_icon_remove_title">Abonnement-ikon (trykk for å fjerne)</string>
<string name="settings_notifications_channel_prefs_summary">Ikke forstyrr (DND) overstyring, lyder osv.</string>
<string name="settings_notifications_channel_prefs_title">Kanalinnstillinger</string>
<string name="detail_settings_global_setting_suffix">ved hjelp av globale innstillinger</string>
<string name="settings_advanced_unifiedpush_summary_disabled">ntfy vil ikke opptre som UnifiedPush-distributør</string>
<string name="settings_advanced_unifiedpush_summary_enabled">ntfy vil opptre som UnifiedPush-distributør</string>
<string name="settings_advanced_unifiedpush_title">Skru på UnifiedPush</string>
</resources>

View file

@ -13,12 +13,12 @@
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<item name="colorPrimary">@color/teal_light</item>
<item name="colorAccent">@color/teal_light</item> <!-- checkboxes, text fields -->
<item name="android:colorBackground">@color/black_900</item> <!-- background -->
<item name="android:statusBarColor">@color/black_900</item>
<item name="actionModeBackground">@color/black_900</item>
<item name="android:colorBackground">@color/black_light</item> <!-- background -->
<item name="android:statusBarColor">@color/black_light</item>
<item name="actionModeBackground">@color/black_light</item>
<!-- Action bar background & text color -->
<item name="colorSurface">@color/black_800b</item>
<item name="colorSurface">@color/gray_dark</item>
<item name="colorOnSurface">@color/white</item>
</style>
@ -27,15 +27,7 @@
</style>
<style name="FloatingActionButton" parent="@style/Widget.MaterialComponents.FloatingActionButton">
<item name="tint">@color/black_900</item>
<item name="tint">@color/black_light</item>
<item name="backgroundTint">@color/teal_light</item>
</style>
<style name="CardView" parent="@style/Widget.MaterialComponents.CardView">
<item name="cardBackgroundColor">@color/black_800b</item>
</style>
<style name="CardViewBackground">
<item name="android:background">@color/black_900</item>
</style>
</resources>

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="channel_notifications_low_name">Lage prioriteit</string>
<string name="channel_notifications_max_name">Maximum prioriteit</string>
<string name="channel_notifications_low_name">Meldingen (lage prioriteit)</string>
<string name="channel_notifications_max_name">Meldingen (max. prioriteit)</string>
<string name="channel_subscriber_notification_instant_text">Geabonneerd op onderwerpen voor directe levering</string>
<string name="channel_subscriber_notification_instant_text_one">Geabonneerd op één onderwerp voor directe levering</string>
<string name="channel_subscriber_notification_instant_text_four">Geabonneerd op vier onderwerpen voor directe levering</string>
@ -16,7 +16,7 @@
<string name="main_banner_battery_button_remind_later">Vraag later</string>
<string name="main_banner_battery_button_dismiss">Afwijzen</string>
<string name="main_banner_battery_button_fix_now">Nu oplossen</string>
<string name="main_banner_websocket_button_remind_later">Vraag later</string>
<string name="main_banner_json_stream_button_remind_later">Vraag later</string>
<string name="add_dialog_title">Abonneren op onderwerp</string>
<string name="add_dialog_login_title">Aanmelden vereist</string>
<string name="add_dialog_button_back">Terug</string>
@ -37,8 +37,8 @@
<string name="add_dialog_button_login">Inloggen</string>
<string name="add_dialog_use_another_server">Gebruik een andere server</string>
<string name="channel_notifications_min_name">Meldingen (min. prioriteit)</string>
<string name="channel_notifications_default_name">Standaard prioriteit</string>
<string name="channel_notifications_high_name">Hoge prioriteit</string>
<string name="channel_notifications_default_name">Meldingen (standaard prioriteit)</string>
<string name="channel_notifications_high_name">Meldingen (hoge prioriteit)</string>
<string name="channel_subscriber_service_name">Abonnementenservice</string>
<string name="main_how_to_intro">Klik op de + om een onderwerp aan te maken of erop te abonneren. Nadien ontvang je meldingen op je toestel bij het verzenden van berichten via PUT or POST.</string>
<string name="channel_subscriber_notification_instant_text_two">Geabonneerd op twee onderwerpen voor directe levering</string>
@ -55,25 +55,25 @@
<string name="refresh_message_error">Kon %1$d abonnementen niet vernieuwen
\n
\n%2$s</string>
<string name="main_menu_notifications_disabled_forever">Meldingen gedempt</string>
<string name="main_menu_notifications_disabled_forever">Meldingen gepauzeerd</string>
<string name="main_action_bar_title">Geabonneerde onderwerpen</string>
<string name="main_action_mode_delete_dialog_cancel">Annuleren</string>
<string name="main_item_status_text_not_one">%1$d meldingen</string>
<string name="main_item_status_reconnecting">opnieuw verbinden …</string>
<string name="main_menu_notifications_enabled">Meldingen aan</string>
<string name="main_menu_notifications_disabled_until">Meldingen gedempt tot %1$s</string>
<string name="main_menu_notifications_disabled_until">Meldingen gepauzeerd tot %1$s</string>
<string name="main_menu_rate_title">Beoordeel de app ⭐</string>
<string name="main_item_status_text_one">%1$d melding</string>
<string name="main_action_mode_delete_dialog_message">Afmelden van de geselecteerde onderwerp(en) en alle meldingen definitief verwijderen\?</string>
<string name="main_item_status_unified_push">%1$s (Unified Push)</string>
<string name="main_item_status_unified_push">%1$s (UnifiedPush)</string>
<string name="main_no_subscriptions_text">Het lijkt erop dat u nog geen abonnementen heeft.</string>
<string name="main_action_mode_delete_dialog_permanently_delete">Permanent verwijderen</string>
<string name="main_unified_push_toast">Dit abonnement wordt beheerd door %1$s via UnifiedPush</string>
<string name="main_banner_battery_text">Batterij optimalisatie zou uitgeschakeld moeten zijn voor deze app om problemen met de bezorging van meldingen te voorkomen.</string>
<string name="main_banner_websocket_button_dismiss">Afwijzen</string>
<string name="main_banner_json_stream_button_dismiss">Afwijzen</string>
<string name="user_dialog_button_delete">Gebruiker verwijderen</string>
<string name="user_dialog_button_cancel">Annuleren</string>
<string name="settings_advanced_connection_protocol_entry_ws">WebSocket</string>
<string name="settings_advanced_connection_protocol_entry_ws">WebSockets</string>
<string name="settings_about_version_title">Versie</string>
<string name="settings_about_header">Over</string>
<string name="settings_advanced_connection_protocol_title">Verbindingsprotocol</string>
@ -86,8 +86,8 @@
<string name="user_dialog_title_add">Gebruiker toevoegen</string>
<string name="settings_advanced_export_logs_uploading">Log uploaden …</string>
<string name="settings_about_version_copied_to_clipboard_message">Gekopieerd naar het klembord</string>
<string name="detail_menu_notifications_disabled_forever">Meldingen gedempt</string>
<string name="detail_menu_notifications_disabled_until">Meldingen gedempt tot %1$s</string>
<string name="detail_menu_notifications_disabled_forever">Meldingen gepauzeerd</string>
<string name="detail_menu_notifications_disabled_until">Meldingen gepauzeerd tot %1$s</string>
<string name="detail_menu_test">Testmelding verzenden</string>
<string name="detail_menu_clear">Alle meldingen wissen</string>
<string name="detail_menu_settings">Abonnementsinstellingen</string>
@ -134,213 +134,4 @@
<string name="detail_item_menu_download">Bestand downloaden</string>
<string name="detail_item_menu_cancel">Download annuleren</string>
<string name="detail_item_menu_copy_contents">Melding kopiëren</string>
<string name="channel_subscriber_notification_title">Luisteren naar inkomende meldingen</string>
<string name="add_dialog_foreground_description">Directe levering staat altijd aan voor andere hosts dan %1$s.</string>
<string name="add_dialog_button_subscribe">Abonneer</string>
<string name="add_dialog_error_connection_failed">Verbinding mislukt: %1$s</string>
<string name="add_dialog_login_description">Dit onderwerp vereist dat je inlogt. Gelieve een gebruikersnaam en wachtwoord in te vullen.</string>
<string name="detail_clear_dialog_message">Verwijder alle notificaties in dit onderwerp\?</string>
<string name="add_dialog_instant_delivery">Onmiddellijke levering in \"doze\" modus</string>
<string name="add_dialog_description_below">Onderwerpen zijn mogelijk niet beveiligd met een wachtwoord, dus kies een naam die moeilijk te raden is. Eenmaal geabonneerd, kunt u berichten PUT/POST\'en.</string>
<string name="add_dialog_use_another_server_description">Vul server URLS hieronder in om te abonneren op onderwerpen van andere servers.</string>
<string name="add_dialog_instant_delivery_description">Zorgt ervoor dat berichten onmiddellijk worden afgeleverd, zelfs als het toestel inactief is.</string>
<string name="add_dialog_login_error_not_authorized">Login gefaald. Gebruiker %1$s is niet geauthoriseerd.</string>
<string name="detail_no_notifications_text">Je hebt nog geen notificaties voor dit onderwerp ontvangen.</string>
<string name="detail_how_to_intro">Om een notificatie naar dit onderwerp te sturen, verstuur een simpele PUT of POST naar de URL van dit onderwerp.</string>
<string name="detail_how_to_example">Voorbeeld (door gebruik van curl): <br/><tt> curl -d \"Hallo\"%1$s</tt></string>
<string name="detail_how_to_link">Gedetaileerde instructies zijn ter beschikking op ntfy.sh en in de documentatie.</string>
<string name="detail_delete_dialog_message">Afmelden voor dit onderwerp en alle notificaties verwijderen\?</string>
<string name="detail_test_title">Test: Je kan een titel aanmaken als je wil.</string>
<string name="detail_instant_delivery_disabled">Directe levering uit</string>
<string name="detail_menu_enable_instant">Directe bezorging inschakelen</string>
<string name="detail_menu_disable_instant">Directe bezorging uitschakelen</string>
<string name="notification_popup_action_open">Openen</string>
<string name="notification_popup_action_browse">Bladeren</string>
<string name="notification_popup_action_download">Downloaden</string>
<string name="settings_backup_restore_backup_entry_everything_no_users">Alles, behalve gebruikers</string>
<string name="settings_backup_restore_restore_successful">Herstel succesvol</string>
<string name="settings_backup_restore_restore_failed">Herstel mislukt: %1$s</string>
<string name="settings_advanced_export_logs_summary">Kopieer logs naar het klembord of upload naar nopaste.net (eigendom van de ntfy auteur). Hostnamen en onderwerpen kunnen worden gecensureerd, meldingen zullen dat nooit zijn.</string>
<string name="settings_advanced_clear_logs_title">Logs verwijderen</string>
<string name="settings_advanced_clear_logs_deleted_toast">Logs verwijderd</string>
<string name="user_dialog_description_add">Je kunt hier een gebruiker toevoegen. Alle onderwerpen voor de opgegeven server zullen deze gebruiker gebruiken.</string>
<string name="settings_advanced_connection_protocol_summary_ws">Gebruik WebSockets om verbinding te maken met de server. Dit is de aangeraden methode, maar deze kan extra configuratie in uw proxy vereisen.</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Gebruik een JSON stream via HTTP om verbinding te maken met de server. Deze methode is getest maar kan meer batterij verbruiken.</string>
<string name="settings_advanced_export_logs_entry_upload_scrubbed">Upload en kopieer link (gecensureerd)</string>
<string name="settings_advanced_export_logs_scrub_dialog_text">Deze onderwerpen/hostnamen zijn vervangen met fruitnamen zodat je het log kunt delen zonder zorgen:
\n
\n%1$s
\n
\nWachtwoorden worden verwijderd, maar worden hier niet vermeld.</string>
<string name="share_topic_title">Delen naar</string>
<string name="settings_notifications_muted_until_forever">Meldingen gedempt totdat ze worden hervat</string>
<string name="settings_notifications_muted_until_x">Meldingen gedempt tot %1$s</string>
<string name="detail_deep_link_subscribed_toast_message">Geabonneerd op onderwerp %1$s</string>
<string name="share_suggested_topics">Voorgestelde onderwerpen</string>
<string name="share_successful">Bericht gepubliceerd</string>
<string name="notification_dialog_title">Meldingen dempen</string>
<string name="notification_dialog_cancel">Annuleren</string>
<string name="notification_dialog_enabled_toast_message">Meldingen hervat</string>
<string name="notification_dialog_muted_forever_toast_message">Meldingen gedempt</string>
<string name="notification_dialog_muted_until_toast_message">Meldingen gedempt tot %1$s</string>
<string name="notification_dialog_show_all">Toon alle meldingen</string>
<string name="notification_popup_file_download_successful">%1$s
\nBestand: %2$s, gedownload</string>
<string name="notification_popup_file_download_failed">%1$s
\nBestand: %2$s, download mislukt</string>
<string name="notification_popup_user_action_failed">%1$s mislukt: %2$s</string>
<string name="settings_notifications_muted_until_title">Meldingen dempen</string>
<string name="settings_notifications_muted_until_show_all">Alle meldingen weergeven</string>
<string name="settings_backup_restore_backup_failed">Back-up mislukt: %1$s</string>
<string name="settings_backup_restore_restore_title">Herstellen vanuit bestand</string>
<string name="settings_advanced_broadcast_summary_enabled">Apps kunnen inkomende meldingen ontvangen als broadcasts</string>
<string name="settings_backup_restore_backup_entry_settings_only">Alleen instellingen</string>
<string name="settings_backup_restore_backup_successful">Back-up aangemaakt</string>
<string name="settings_advanced_broadcast_title">Berichten broadcasten</string>
<string name="settings_advanced_broadcast_summary_disabled">Apps kunnen geen meldingen ontvangen als broadcasts</string>
<string name="settings_backup_restore_backup_entry_everything">Alles</string>
<string name="settings_advanced_export_logs_title">Kopieer/upload logs</string>
<string name="settings_advanced_export_logs_entry_copy_original">Kopieer naar klembord</string>
<string name="settings_advanced_export_logs_entry_copy_scrubbed">Kopiëren naar klembord (gecensureerd)</string>
<string name="settings_advanced_export_logs_entry_upload_original">Upload en kopieer link</string>
<string name="settings_advanced_export_logs_copied_logs">Logs gekopieerd naar klembord</string>
<string name="settings_advanced_export_logs_scrub_dialog_button_ok">Oké</string>
<string name="settings_advanced_clear_logs_summary">Verwijder eerder opgenomen logs en begin opnieuw</string>
<string name="user_dialog_description_edit">Je kunt de gebruikersnaam/wachtwoord voor de geselecteerde gebruiker bewerken of verwijderen.</string>
<string name="detail_test_message">Dit is een testnotificatie van de ntfy Android app. De prioriteit is level %1$d. Als je een andere notificatie stuurt, kan die er anders uit zien.</string>
<string name="detail_test_message_error">Kan het bericht niet versturen: %1$s</string>
<string name="detail_test_message_error_unauthorized_anon">Kan bericht niet versturen: Anoniem publiceren niet toegestaan.</string>
<string name="detail_test_message_error_unauthorized_user">Kan bericht niet versturen: De gebruiker \"%1$s\" is niet geautoriseerd.</string>
<string name="detail_test_message_error_too_large">Kan bericht niet versturen: De bijlage is te groot.</string>
<string name="detail_copied_to_clipboard_message">Gekopieerd naar het klembord</string>
<string name="detail_instant_delivery_enabled">Directe levering aan</string>
<string name="detail_item_tags">Tags: %1$s</string>
<string name="detail_item_snack_deleted">Notificatie verwijderd</string>
<string name="notification_dialog_save">Opslaan</string>
<string name="notification_popup_action_cancel">Annuleren</string>
<string name="notification_popup_file">%1$s
\nBestand: %2$s</string>
<string name="notification_popup_file_downloading">Downloaden %1$s, %2$d%%
\n%3$s</string>
<string name="settings_backup_restore_restore_summary">Configuratie, meldingen en gebruikers importeren</string>
<string name="settings_advanced_header">Geavanceerd</string>
<string name="settings_advanced_record_logs_title">Logs opnemen</string>
<string name="settings_advanced_record_logs_summary_enabled">Loggen (tot 1,000 vermeldingen) naar apparaat …</string>
<string name="settings_advanced_record_logs_summary_disabled">Loggen inschakelen, deze kan later gedeeld worden om problemen te analyseren.</string>
<string name="settings_advanced_export_logs_scrub_dialog_empty">Er zijn geen onderwerpen/hostnamen gecensureerd. Misschien heb je geen abonnementen\?</string>
<string name="detail_item_download_info_deleted">verwijderd</string>
<string name="settings_notifications_auto_download_always">Alles automatisch downloaden</string>
<string name="settings_notifications_auto_download_never">Nooit automatisch downloaden</string>
<string name="settings_notifications_auto_download_5m">Als kleiner dan 5 MB</string>
<string name="settings_notifications_auto_delete_summary_three_days">Meldingen automatisch verwijderen na drie dagen</string>
<string name="settings_notifications_auto_delete_never">Nooit</string>
<string name="settings_notifications_auto_delete_one_day">Na één dag</string>
<string name="detail_item_cannot_open_url">URL: %1$s kan niet worden geopend</string>
<string name="detail_item_cannot_open_not_found">Bijlage kan niet worden geopend: Het bestand kan verwijderd zijn, of er geen app aanwezig die het bestand kan openen.</string>
<string name="channel_subscriber_notification_instant_text_five">Geabonneerd op vijf onderwerpen voor directe levering</string>
<string name="detail_item_cannot_open">Bijlage: %1$s kan niet worden geopend</string>
<string name="channel_subscriber_notification_noinstant_text_five">Geabonneerd op vijf onderwerpen</string>
<string name="share_content_image_text">Er is een afbeelding met je gedeeld</string>
<string name="settings_notifications_min_priority_summary_any">Alle notificaties worden weergegeven</string>
<string name="settings_notifications_channel_prefs_title">Kanaal instellingen</string>
<string name="settings_notifications_auto_download_500k">Als kleiner dan 500 kB</string>
<string name="detail_item_download_info_downloading_x_percent">%1$d gedownload</string>
<string name="detail_item_download_info_deleted_expires_x">verwijderd, link vervalt %1$s</string>
<string name="settings_notifications_min_priority_summary_x_or_higher">Toon notificaties als prioriteit is %1$d (%2$s) of hoger</string>
<string name="detail_item_download_info_download_failed_expires_x">download mislukt, link vervalt %1$s</string>
<string name="share_content_text_hint">Voeg content om te delen toe</string>
<string name="share_content_image_error">Afbeelding: %1$s kan niet worden gelezen</string>
<string name="share_content_file_error">Bestandsinformatie van: %1$s kan niet worden gelezen</string>
<string name="settings_notifications_min_priority_max">Alleen maximale prioriteit</string>
<string name="settings_notifications_priority_min">min</string>
<string name="settings_notifications_priority_low">laag</string>
<string name="settings_notifications_auto_download_100k">Als kleiner dan 100 kB</string>
<string name="settings_general_default_base_url_message">Voer de root URL in van je eigen server om deze standaard te gebruiken bij abonneren op nieuwe onderwerpen en/of delen in onderwerpen.</string>
<string name="detail_settings_appearance_icon_error_saving">Kan icoon: %1$s niet bewaren</string>
<string name="settings_general_users_prefs_user_used_by_many">Gebruikt in onderwerpen %1$s</string>
<string name="settings_general_users_prefs_user_not_used">In geen enkel onderwerp in gebruik</string>
<string name="settings_general_users_prefs_user_used_by_one">Gebruikt in onderwerp %1$s</string>
<string name="settings_general_dark_mode_entry_system">Gebruik systeem standaard</string>
<string name="detail_settings_notifications_instant_summary_on">Notificaties worden direct afgeleverd. Dit vereist een service in de voorgrond en verbruikt meer batterij.</string>
<string name="detail_settings_appearance_icon_remove_summary">Icoon wat zal worden weergegeven in notificaties voor dit onderwerp</string>
<string name="detail_settings_global_setting_title">Gebruik globale instelling</string>
<string name="settings_notifications_min_priority_summary_max">Toon notificaties als prioriteit is 5 (max)</string>
<string name="settings_notifications_priority_default">standaard</string>
<string name="settings_notifications_auto_download_summary_never">Bijlages nooit automatisch downloaden</string>
<string name="settings_notifications_auto_download_10m">Als kleiner dan 10 MB</string>
<string name="settings_notifications_auto_delete_summary_never">Meldingen nooit automatisch verwijderen</string>
<string name="settings_notifications_priority_high">hoog</string>
<string name="settings_notifications_channel_prefs_summary">Niet Storen (DND), geluiden, etc.</string>
<string name="settings_notifications_auto_download_title">Bijlages downloaden</string>
<string name="settings_notifications_priority_max">max</string>
<string name="settings_general_dark_mode_title">Donkere modus</string>
<string name="settings_notifications_auto_delete_summary_one_week">Meldingen automatisch verwijderen na één week</string>
<string name="channel_subscriber_notification_instant_text_six">Geabonneerd op zes onderwerpen voor directe levering</string>
<string name="channel_subscriber_notification_noinstant_text_six">Geabonneerd op zes onderwerpen</string>
<string name="detail_item_cannot_download">Bijlage kan niet geopend of gedownload worden. De link is verlopen en een lokaal bestand kan niet worden gevonden.</string>
<string name="detail_item_cannot_save">Bijlage: %1$s kan niet worden bewaard</string>
<string name="detail_item_cannot_delete">Bijlage: %1$s kan niet worden verwijderd</string>
<string name="detail_item_download_failed">Bijlage: %1$s kan niet worden gedownload</string>
<string name="detail_item_download_info_not_downloaded">niet gedownload</string>
<string name="detail_item_download_info_not_downloaded_expired">niet gedownload, link is verlopen</string>
<string name="detail_item_download_info_not_downloaded_expires_x">niet gedownload, verloopt %1$s</string>
<string name="detail_item_download_info_deleted_expired">verwijderd, link is verlopen</string>
<string name="detail_item_download_info_download_failed">download mislukt</string>
<string name="detail_item_download_info_download_failed_expired">download mislukt, link is verlopen</string>
<string name="share_content_file_text">Er is een bestand met je gedeeld</string>
<string name="settings_notifications_min_priority_min">Iedere prioriteit</string>
<string name="settings_notifications_min_priority_low">Lage prioriteit en hoger</string>
<string name="settings_notifications_min_priority_default">Standaard prioriteit en hoger</string>
<string name="settings_notifications_min_priority_high">Hoge prioriteit en hoger</string>
<string name="settings_notifications_auto_download_summary_always">Bijlages automatisch downloaden</string>
<string name="settings_notifications_auto_download_50m">Als kleiner dan 50 MB</string>
<string name="settings_notifications_auto_delete_summary_one_month">Meldingen automatisch verwijderen na één maand</string>
<string name="settings_notifications_auto_delete_summary_three_months">Meldingen automatisch verwijderen na drie maanden</string>
<string name="settings_notifications_auto_delete_one_week">Na één week</string>
<string name="settings_notifications_auto_delete_one_month">Na één maand</string>
<string name="settings_notifications_auto_delete_three_months">Na 3 maanden</string>
<string name="settings_notifications_auto_delete_three_days">Na 3 dagen</string>
<string name="settings_general_default_base_url_default_summary">%1$s (standaard)</string>
<string name="settings_notifications_auto_download_1m">Als kleiner dan 1 MB</string>
<string name="settings_general_users_prefs_title">Gebruikers</string>
<string name="settings_general_users_prefs_user_add">Gebruikers toevoegen</string>
<string name="settings_general_users_prefs_user_add_title">Nieuwe gebruiker toevoegen</string>
<string name="settings_general_users_prefs_user_add_summary">Creëer een nieuwe gebruiker voor een nieuwe server</string>
<string name="settings_general_dark_mode_summary_system">Gebruik de systeem standaard</string>
<string name="settings_general_dark_mode_summary_light">Lichte modus aan</string>
<string name="settings_general_dark_mode_summary_dark">Donkere modus aan. Ben je een vampier\?</string>
<string name="settings_general_dark_mode_entry_light">Lichte modus</string>
<string name="detail_settings_notifications_instant_title">Directe levering</string>
<string name="detail_settings_notifications_instant_summary_off">Notificaties worden afgeleverd via Firebase. Aflevering kan iets vertraagd zijn, maar dit verbruikt minder batterij.</string>
<string name="detail_settings_appearance_header">Weergave</string>
<string name="detail_settings_appearance_icon_set_title">Abonnement icoon</string>
<string name="detail_settings_appearance_icon_set_summary">Stel een icoon in wat zal worden weergegeven in notificaties</string>
<string name="detail_settings_appearance_icon_remove_title">Abonnementen icoon (tap om te verwijderen)</string>
<string name="detail_settings_global_setting_suffix">Gebruikt globale instelling</string>
<string name="detail_settings_appearance_display_name_default_summary">%1$s (standaard)</string>
<string name="detail_settings_appearance_display_name_title">Schermnaam</string>
<string name="detail_settings_appearance_display_name_message">Zet een schermnaam voor dit abonnement. Laat het veld leeg om de standaard naam te kiezen (%1$s).</string>
<string name="detail_settings_about_header">Over</string>
<string name="detail_settings_about_topic_url_title">Onderwerp URL</string>
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">Gekopieerd naar klembord</string>
<string name="add_dialog_base_urls_dropdown_choose">Kies service URL</string>
<string name="add_dialog_base_urls_dropdown_clear">Service URL verwijderen</string>
<string name="main_banner_websocket_button_enable_now">Nu inschakelen</string>
<string name="main_banner_websocket_text">WebSockets is de aangeraden manier om te verbinden met uw server en kan batterij verbruik verminderen. Het kan <a href="https://ntfy.sh/docs/config/#nginxapache2caddy"> extra configuratie in uw proxy</a> vereisen. Dit kan omgeschakeld worden in de instellingen.</string>
<string name="channel_notifications_group_default_name">Standaard</string>
<string name="main_menu_donate_title">Doneer 💸</string>
<string name="detail_item_cannot_open_apk">Apps kunnen niet meer worden geïnstalleerd. Download deze via de browser. Raadpleeg issue #531 voor meer details.</string>
<string name="settings_notifications_insistent_max_priority_title">Behoud meldingen voor hoogste prioriteit</string>
<string name="settings_notifications_insistent_max_priority_summary_enabled">Max prioriteit berichten geven continue een melding totdat deze worden gesloten</string>
<string name="settings_notifications_insistent_max_priority_summary_disabled">Max prioriteit berichten geven eenmalig een melding</string>
<string name="detail_settings_notifications_dedicated_channels_title">Instellingen voor aangepaste melding</string>
<string name="detail_settings_notifications_dedicated_channels_summary_on">Aangepaste instellingen in gebruik voor dit abonnement</string>
<string name="detail_settings_notifications_open_channels_title">Aanpassen instellingen voor meldingen</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_enabled">Blijven melden</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_disabled">Eenmalig melden</string>
<string name="detail_settings_notifications_dedicated_channels_summary_off">Standaard instellingen in gebruik (geluiden, Niet storen, etc.)</string>
<string name="detail_settings_notifications_open_channels_summary">Niet storen (DND) negeren, geluiden, etc.</string>
<string name="settings_advanced_unifiedpush_summary_enabled">ntfy zal optreden als UnifiedPush-distributeur</string>
<string name="settings_advanced_unifiedpush_title">UnifiedPush inschakelen</string>
<string name="settings_advanced_unifiedpush_summary_disabled">ntfy treedt niet op als UnifiedPush-distributeur</string>
</resources>

View file

@ -1,346 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="channel_notifications_min_name">Minimalny priorytet</string>
<string name="channel_notifications_low_name">Niski priorytet</string>
<string name="channel_notifications_default_name">Domyślny priorytet</string>
<string name="channel_notifications_max_name">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 natychmiastowym dostarczaniem</string>
<string name="channel_notifications_high_name">Wysoki priorytet</string>
<string name="channel_subscriber_service_name">Usługa subskrypcji</string>
<string name="add_dialog_login_username_hint">Nazwa użytkownika</string>
<string name="detail_action_mode_delete_dialog_message">Usunąć wybrane powiadomienie(a) trwale\?</string>
<string name="detail_action_mode_delete_dialog_cancel">Anuluj</string>
<string name="notification_dialog_save">Zapisz</string>
<string name="settings_title">Ustawienia</string>
<string name="settings_notifications_muted_until_title">Wycisz powiadomienia</string>
<string name="settings_notifications_muted_until_forever">Powiadomienia wyciszone do wznowienia</string>
<string name="settings_notifications_min_priority_default">Podstawowy priorytet i wyższy</string>
<string name="settings_notifications_auto_delete_title">Usuń powiadomienia</string>
<string name="settings_general_dark_mode_title">Tryb ciemny</string>
<string name="settings_backup_restore_restore_failed">Przywracanie nie powiodło się: %1$s</string>
<string name="settings_advanced_clear_logs_deleted_toast">Logi usunięte</string>
<string name="user_dialog_base_url_hint">Adres URL usługi</string>
<string name="detail_settings_appearance_display_name_title">Nazwa wyświetlana</string>
<string name="detail_settings_appearance_display_name_default_summary">%1$s (domyślny)</string>
<string name="user_dialog_title_edit">Edytuj użytkownika</string>
<string name="user_dialog_description_add">Tutaj możesz dodać użytkownika. Wszystkie tematy na podanym serwerze będą wtedy korzystać z tego użytkownika.</string>
<string name="user_dialog_description_edit">Możesz zmienić lub usunąć nazwę użytkownika/hasło dla wybranego użytkownika.</string>
<string name="user_dialog_username_hint">Nazwa użytkownika</string>
<string name="notification_dialog_muted_until_toast_message">Powiadomienia wyciszone przez %1$s</string>
<string name="detail_item_menu_download">Pobierz plik</string>
<string name="detail_action_mode_menu_copy">Kopiuj</string>
<string name="detail_menu_clear">Wyczyść powiadomienia</string>
<string name="detail_item_menu_delete">Usuń plik</string>
<string name="detail_item_menu_cancel">Anuluj pobieranie</string>
<string name="detail_item_cannot_open_url">Nie można otworzyć adresu URL: %1$s</string>
<string name="detail_item_download_info_download_failed_expires_x">pobieranie nie powiodło się, link wygasa %1$s</string>
<string name="share_content_text_hint">Dodaj treść do udostępnienia</string>
<string name="share_content_image_error">Nie można odczytać obrazu: %1$s</string>
<string name="notification_dialog_show_all">Pokaż wszystkie powiadomienia</string>
<string name="notification_dialog_30min">30 minut</string>
<string name="notification_dialog_1h">1 godzina</string>
<string name="notification_dialog_8h">8 godzin</string>
<string name="notification_dialog_forever">Do wznowienia</string>
<string name="settings_notifications_auto_download_500k">Jeśli poniżej 500 kB</string>
<string name="settings_notifications_channel_prefs_title">Ustawienia kanału</string>
<string name="settings_notifications_auto_delete_summary_three_months">Automatycznie usuń powiadomienia po 3 miesiącach</string>
<string name="settings_notifications_auto_download_5m">Jeśli poniżej 5 MB</string>
<string name="settings_notifications_auto_delete_summary_never">Nigdy nie usuwaj powiadomień automatycznie</string>
<string name="settings_general_users_prefs_title">Użytkownicy</string>
<string name="settings_general_dark_mode_summary_light">Tryb jasny włączony</string>
<string name="settings_general_dark_mode_entry_system">Użyj domyślnych ustawień systemu</string>
<string name="settings_general_dark_mode_entry_light">Tryb jasny</string>
<string name="settings_general_dark_mode_entry_dark">Tryb ciemny</string>
<string name="settings_advanced_broadcast_summary_disabled">Aplikacje nie mogą odbierać powiadomień jako transmisje</string>
<string name="settings_advanced_export_logs_entry_copy_original">Kopiuj do schowka</string>
<string name="settings_advanced_export_logs_entry_copy_scrubbed">Kopiuj do schowka (ocenzurowane)</string>
<string name="settings_advanced_export_logs_scrub_dialog_text">Te tematy / nazwy hostów zostały zastąpione nazwami owoców, więc możesz udostępnić dziennik bez obaw:
\n
\n%1$s
\n
\nHasła zostały usunięte, ale nie są tutaj wymienione.</string>
<string name="settings_advanced_record_logs_summary_disabled">Włącz rejestrowanie, aby móc później udostępnić logi w celu zdiagnozowania problemów.</string>
<string name="channel_subscriber_notification_instant_text_two">Zasubskrybowano do dwóch tematów z natychmiastową dostawą</string>
<string name="settings_advanced_export_logs_summary">Kopiuj logi do schowka, lub prześlij na nopaste.net (własność autora ntfy). Nazwy hostów i tematy mogą być cenzurowane, powiadomienia nigdy nie będą.</string>
<string name="channel_subscriber_notification_noinstant_text_six">Zasubskrybowano sześć tematów</string>
<string name="channel_subscriber_notification_instant_text_more">Zasubskrybowano do %1$d tematów z natychmiastową dostawą</string>
<string name="detail_settings_notifications_instant_summary_off">Powiadomienia są dostarczane za pomocą Firebase. Dostarczanie może być opóźnione, ale zużywa mniej baterii.</string>
<string name="channel_subscriber_notification_noinstant_text_five">Zasubskrybowano pięć tematów</string>
<string name="add_dialog_use_another_server_description">Wpisz poniżej adresy URL serwisów, aby subskrybować tematy z innych serwerów.</string>
<string name="detail_clear_dialog_permanently_delete">Usuń trwale</string>
<string name="main_how_to_intro">Kliknij +, aby utworzyć lub zasubskrybować temat. Następnie otrzymasz powiadomienia na swoim urządzeniu, gdy wiadomości zostaną opublikowane za pośrednictwem PUT lub POST.</string>
<string name="main_item_status_text_not_one">%1$d powiadomienia</string>
<string name="main_add_button_description">Dodaj subskrypcję</string>
<string name="main_item_status_reconnecting">ponowne połączenie …</string>
<string name="main_no_subscriptions_text">Wygląda na to, że nie masz jeszcze żadnych subskrypcji.</string>
<string name="detail_no_notifications_text">Nie otrzymałeś jeszcze żadnych powiadomień dla tego tematu.</string>
<string name="detail_test_message">To jest testowe powiadomienie z aplikacji ntfy na Androida. Ma ono priorytet na poziomie %1$d. Jeśli wyślesz kolejne, może ono wyglądać inaczej.</string>
<string name="detail_item_download_info_deleted_expired">usunięto, łącze wygasło</string>
<string name="settings_advanced_connection_protocol_summary_ws">Użyj WebSockets, aby połączyć się z serwerem. Jest to zalecana metoda, ale może wymagać dodatkowej konfiguracji w twoim proxy.</string>
<string name="detail_settings_appearance_display_name_message">Ustaw niestandardową nazwę wyświetlaną dla tej subskrypcji. Pozostaw puste dla domyślnej (%1$s).</string>
<string name="detail_settings_global_setting_title">Użyj ustawienia globalnego</string>
<string name="share_menu_send">Udostępnij</string>
<string name="notification_dialog_2h">2 godziny</string>
<string name="notification_dialog_tomorrow">Do jutra</string>
<string name="notification_popup_action_cancel">Anuluj</string>
<string name="settings_notifications_auto_delete_summary_one_day">Automatycznie usuń powiadomienia po jednym dniu</string>
<string name="settings_notifications_auto_delete_summary_three_days">Automatycznie usuń powiadomienia po 3 dniach</string>
<string name="settings_notifications_auto_delete_one_month">Po miesiącu</string>
<string name="settings_notifications_min_priority_high">Wysoki priorytet i wyższy</string>
<string name="notification_popup_user_action_failed">%1$s nie powiodło się: %2$s</string>
<string name="settings_backup_restore_header">Kopia zapasowa &amp; Przywracanie</string>
<string name="settings_backup_restore_backup_summary">Eksportuj konfigurację, powiadomienia i użytkowników</string>
<string name="settings_advanced_export_logs_entry_upload_scrubbed">Prześlij i kopiuj łącze (ocenzurowane)</string>
<string name="channel_subscriber_notification_noinstant_text">Zasubskrybowane tematy</string>
<string name="main_how_to_link">Szczegółowe instrukcje są dostępne w ntfy.sh, oraz w dokumentacji.</string>
<string name="main_banner_battery_text">Optymalizacja baterii powinna być wyłączona dla aplikacji, aby uniknąć problemów z dostarczaniem powiadomień.</string>
<string name="main_menu_rate_title">Oceń aplikację ⭐</string>
<string name="main_action_mode_delete_dialog_message">Zrezygnować z wybranego tematu/ów i trwale usunąć wszystkie powiadomienia\?</string>
<string name="main_action_mode_delete_dialog_permanently_delete">Usuń trwale</string>
<string name="add_dialog_foreground_description">Natychmiastowe dostarczanie jest zawsze włączone dla hostów innych niż %1$s.</string>
<string name="add_dialog_button_back">Powrót</string>
<string name="add_dialog_error_connection_failed">Połączenie nieudane: %1$s</string>
<string name="add_dialog_button_login">Zaloguj się</string>
<string name="add_dialog_button_subscribe">Subskrybuj</string>
<string name="add_dialog_login_password_hint">Hasło</string>
<string name="add_dialog_instant_delivery_description">Zapewnia natychmiastowe dostarczanie wiadomości, nawet jeśli urządzenie jest nieaktywne.</string>
<string name="add_dialog_login_title">Wymagane jest zalogowanie się</string>
<string name="add_dialog_instant_delivery">Natychmiastowe dostarczanie w trybie drzemki</string>
<string name="detail_delete_dialog_permanently_delete">Usuń trwale</string>
<string name="detail_delete_dialog_cancel">Anuluj</string>
<string name="detail_test_title">Test: Jeśli chcesz, możesz ustawić tytuł.</string>
<string name="detail_instant_delivery_disabled">Natychmiastowe dostarczanie wyłączone</string>
<string name="detail_test_message_error">Nie można wysłać wiadomości: %1$s</string>
<string name="detail_instant_delivery_enabled">Natychmiastowe dostarczanie włączone</string>
<string name="detail_test_message_error_unauthorized_anon">Nie można wysłać wiadomości: Anonimowa publikacja nie jest dozwolona.</string>
<string name="detail_test_message_error_unauthorized_user">Nie można wysłać wiadomości: Użytkownik \"%1$s\" nie ma uprawnień.</string>
<string name="detail_test_message_error_too_large">Nie można wysłać wiadomości: Załącznik jest zbyt duży.</string>
<string name="detail_copied_to_clipboard_message">Skopiowano do schowka</string>
<string name="detail_item_cannot_delete">Nie można usunąć załącznika: %1$s</string>
<string name="detail_item_download_failed">Nie można pobrać załącznika: %1$s</string>
<string name="detail_item_download_info_not_downloaded">nie pobrany</string>
<string name="detail_item_download_info_not_downloaded_expired">nie pobrany, link wygasł</string>
<string name="detail_item_download_info_not_downloaded_expires_x">nie pobrany, wygasa %1$s</string>
<string name="detail_menu_notifications_enabled">Powiadomienia włączone</string>
<string name="detail_menu_test">Wyślij powiadomienie testowe</string>
<string name="detail_menu_copy_url">Kopiuj adres tematu</string>
<string name="detail_menu_unsubscribe">Zrezygnuj z subskrypcji</string>
<string name="detail_action_mode_menu_delete">Usuń</string>
<string name="detail_menu_disable_instant">Wyłącz natychmiastowe dostarczanie</string>
<string name="detail_item_download_info_download_failed_expired">pobieranie nie powiodło się, łącze wygasło</string>
<string name="share_content_file_text">Podzielono się z Tobą plikiem</string>
<string name="share_content_file_error">Nie można odczytać informacji o pliku: %1$s</string>
<string name="share_topic_title">Udostępnij do</string>
<string name="notification_dialog_cancel">Anuluj</string>
<string name="notification_popup_action_open">Otwórz</string>
<string name="notification_popup_action_browse">Przeglądaj</string>
<string name="notification_popup_action_download">Pobierz</string>
<string name="settings_notifications_auto_delete_summary_one_week">Automatycznie usuń powiadomienia po tygodniu</string>
<string name="settings_general_default_base_url_title">Serwer domyślny</string>
<string name="settings_advanced_broadcast_summary_enabled">Aplikacje mogą odbierać przychodzące powiadomienia jako transmisje</string>
<string name="settings_about_header">Informacje o</string>
<string name="user_dialog_button_add">Dodaj użytkownika</string>
<string name="main_menu_notifications_disabled_forever">Powiadomienia wyciszone</string>
<string name="main_menu_notifications_enabled">Powiadomienia włączone</string>
<string name="add_dialog_login_new_user">Nowy użytkownik</string>
<string name="add_dialog_description_below">Tematy mogą nie być chronione hasłem, więc wybierz nazwę, która jest trudna do odgadnięcia. Po subskrypcji możesz wysyłać powiadomienia PUT/POST.</string>
<string name="add_dialog_title">Zasubskrybuj temat</string>
<string name="add_dialog_topic_name_hint">Nazwa tematu, np. moje_powiadomienia</string>
<string name="add_dialog_use_another_server">Użyj innego serwera</string>
<string name="add_dialog_login_description">Ten temat wymaga zalogowania. Proszę podaj nazwę użytkownika i hasło.</string>
<string name="add_dialog_login_error_not_authorized">Logowanie nie powiodło się. Użytkownik %1$s nie jest upoważniony.</string>
<string name="channel_subscriber_notification_instant_text_five">Zasubskrybowano do pięciu tematów z natychmiastowym dostarczaniem</string>
<string name="channel_subscriber_notification_instant_text_six">Zasubskrybowano do sześciu tematów z natychmiastowym dostarczaniem</string>
<string name="channel_subscriber_notification_noinstant_text_two">Zasubskrybowano dwa tematy</string>
<string name="channel_subscriber_notification_noinstant_text_one">Zasubskrybowano jeden temat</string>
<string name="channel_subscriber_notification_noinstant_text_more">Zasubskrybowano %1$d tematów</string>
<string name="refresh_message_no_results">Wszystko jest aktualne</string>
<string name="refresh_message_error">Nie można odświeżyć %1$d subskrypcji
\n
\n%2$s</string>
<string name="refresh_message_error_one">Nie można odświeżyć subskrypcji: %1$s</string>
<string name="channel_subscriber_notification_noinstant_text_three">Zasubskrybowano trzy tematy</string>
<string name="channel_subscriber_notification_noinstant_text_four">Zasubskrybowano cztery tematy</string>
<string name="detail_clear_dialog_cancel">Anuluj</string>
<string name="detail_deep_link_subscribed_toast_message">Temat %1$s zasubskrybowany</string>
<string name="detail_item_snack_deleted">Powiadomienie usunięte</string>
<string name="detail_item_snack_undo">Cofnij</string>
<string name="settings_general_users_prefs_user_used_by_one">Używane przez temat %1$s</string>
<string name="settings_general_users_prefs_user_not_used">Nieużywane przez żadne tematy</string>
<string name="settings_advanced_clear_logs_title">Wyczyść logi</string>
<string name="settings_advanced_connection_protocol_entry_ws">WebSockety</string>
<string name="detail_settings_global_setting_suffix">przy użyciu ustawienia globalnego</string>
<string name="detail_settings_about_header">Informacje o</string>
<string name="detail_settings_about_topic_url_title">Adres URL tematu</string>
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">Skopiowano do schowka</string>
<string name="user_dialog_password_hint_add">Hasło</string>
<string name="user_dialog_password_hint_edit">Hasło (niezmienione, jeśli pozostawiono puste)</string>
<string name="user_dialog_button_delete">Usuń użytkownika</string>
<string name="user_dialog_button_save">Zapisz</string>
<string name="main_menu_notifications_disabled_until">Powiadomienia wyciszone przez %1$s</string>
<string name="main_action_mode_delete_dialog_cancel">Anuluj</string>
<string name="main_menu_docs_title">Przeczytaj dokumentację</string>
<string name="main_action_bar_title">Subskrybowane tematy</string>
<string name="main_menu_settings_title">Ustawienia</string>
<string name="main_item_status_unified_push">%1$s (UnifiedPush)</string>
<string name="main_menu_report_bug_title">Zgłoś błąd</string>
<string name="main_action_mode_menu_unsubscribe">Zrezygnuj z subskrypcji</string>
<string name="channel_subscriber_notification_instant_text_one">Zasubskrybowano jeden temat z natychmiastową dostawą</string>
<string name="channel_subscriber_notification_instant_text_three">Zasubskrybowano do trzech tematów z natychmiastową dostawą</string>
<string name="channel_subscriber_notification_instant_text_four">Zasubskrybowano do czterech tematów z natychmiastową dostawą</string>
<string name="refresh_message_result">Otrzymano %1$d powiadomień</string>
<string name="main_item_status_text_one">%1$d powiadomienie</string>
<string name="main_unified_push_toast">Ta subskrypcja jest zarządzana przez %1$s poprzez UnifiedPush</string>
<string name="main_banner_battery_button_remind_later">Zapytaj później</string>
<string name="main_banner_battery_button_dismiss">Odrzuć</string>
<string name="main_banner_battery_button_fix_now">Napraw teraz</string>
<string name="add_dialog_button_cancel">Anuluj</string>
<string name="main_item_date_yesterday">wczoraj</string>
<string name="detail_delete_dialog_message">Zrezygnować z subskrypcji tego tematu i usunąć wszystkie otrzymane powiadomienia\?</string>
<string name="detail_menu_enable_instant">Włącz natychmiastowe dostarczanie</string>
<string name="detail_menu_notifications_disabled_forever">Powiadomienia wyciszone</string>
<string name="detail_menu_notifications_disabled_until">Powiadomienia wyciszone przez %1$s</string>
<string name="user_dialog_button_cancel">Anuluj</string>
<string name="add_dialog_base_urls_dropdown_clear">Wyczyść adres URL usługi</string>
<string name="detail_item_menu_save_file">Zapisz plik</string>
<string name="detail_item_cannot_save">Nie można zapisać załącznika: %1$s</string>
<string name="detail_item_menu_open">Otwórz plik</string>
<string name="detail_item_menu_copy_url">Kopiuj Adres URL</string>
<string name="detail_item_menu_copy_url_copied">Adres URL skopiowany do schowka</string>
<string name="detail_item_menu_copy_contents">Kopiuj powiadomienie</string>
<string name="detail_item_menu_copy_contents_copied">Powiadomienie skopiowane do schowka</string>
<string name="detail_item_saved_successfully">Zapisane jako \"%1$s\" w folderze \"Downloads\"</string>
<string name="detail_item_cannot_download">Nie można otworzyć lub pobrać załącznika. Link wygasł i nie można było znaleźć lokalnego pliku.</string>
<string name="detail_item_cannot_open">Nie można otworzyć załącznika: %1$s</string>
<string name="detail_item_cannot_open_not_found">Nie można otworzyć załącznika: Plik mógł zostać usunięty lub żadna zainstalowana aplikacja nie może go otworzyć.</string>
<string name="detail_item_download_info_downloading_x_percent">%1$d%% pobrano</string>
<string name="detail_menu_settings">Ustawienia subskrypcji</string>
<string name="detail_action_mode_delete_dialog_permanently_delete">Usuń trwale</string>
<string name="detail_settings_title">Ustawienia subskrypcji</string>
<string name="share_title">Udostępnij</string>
<string name="share_content_title">Podgląd wiadomości</string>
<string name="add_dialog_base_urls_dropdown_choose">Wybierz adres URL usługi</string>
<string name="detail_how_to_intro">Aby wysłać powiadomienia do tego tematu, wyślij PUT lub POST-Request na adres URL tematu.</string>
<string name="detail_how_to_example">Przykład (za pomocą curl):<br/><tt>$ curl -d \"Cześć\" %1$s</tt></string>
<string name="detail_how_to_link">Szczegółowe instrukcje są dostępne w ntfy.sh, oraz w dokumentacji.</string>
<string name="detail_clear_dialog_message">Usunąć wszystkie powiadomienia z tego tematu\?</string>
<string name="detail_item_tags">Tagi: %1$s</string>
<string name="detail_item_download_info_deleted">usunięto</string>
<string name="detail_item_download_info_deleted_expires_x">usunięto, łącze wygasa %1$s</string>
<string name="detail_item_download_info_download_failed">pobieranie nie powiodło się</string>
<string name="share_content_image_text">Podzielono się z Tobą obrazem</string>
<string name="share_suggested_topics">Sugerowane tematy</string>
<string name="share_successful">Wiadomość opublikowana</string>
<string name="notification_dialog_title">Wycisz powiadomienia</string>
<string name="notification_dialog_enabled_toast_message">Powiadomienia wznowione</string>
<string name="notification_dialog_muted_forever_toast_message">Powiadomienia wyciszone</string>
<string name="notification_popup_file">%1$s
\nPlik: %2$s</string>
<string name="notification_popup_file_downloading">Pobieranie %1$s, %2$d%%
\n%3$s</string>
<string name="notification_popup_file_download_successful">%1$s
\nPlik: %2$s, pobrany</string>
<string name="notification_popup_file_download_failed">%1$s
\nPlik: %2$s, pobieranie nie powiodło się</string>
<string name="settings_notifications_header">Powiadomienia</string>
<string name="settings_notifications_muted_until_show_all">Wszystkie powiadomienia</string>
<string name="settings_notifications_muted_until_x">Powiadomienia wyciszone przez %1$s</string>
<string name="settings_notifications_min_priority_title">Minimalny priorytet</string>
<string name="settings_notifications_min_priority_summary_any">Wszystkie powiadomienia</string>
<string name="settings_notifications_min_priority_summary_x_or_higher">Pokaż powiadomienia, jeśli priorytet jest %1$d (%2$s) lub wyższy</string>
<string name="settings_notifications_min_priority_summary_max">Pokaż powiadomienia, jeśli priorytet wynosi 5 (max)</string>
<string name="settings_notifications_min_priority_min">Dowolny priorytet</string>
<string name="settings_notifications_min_priority_low">Niski priorytet i wyższy</string>
<string name="settings_notifications_min_priority_max">Tylko maksymalny priorytet</string>
<string name="settings_notifications_priority_min">minimum</string>
<string name="settings_notifications_priority_low">niski</string>
<string name="settings_notifications_priority_default">podstawowy</string>
<string name="settings_notifications_priority_high">wysoki</string>
<string name="settings_notifications_priority_max">maksymalny</string>
<string name="settings_notifications_auto_download_title">Pobierz załączniki</string>
<string name="settings_notifications_auto_download_summary_always">Automatycznie pobierz wszystkie załączniki</string>
<string name="settings_notifications_auto_download_summary_never">Nigdy automatycznie nie pobieraj wszystkich załączników</string>
<string name="settings_notifications_auto_download_summary_smaller_than_x">Automatycznie pobierz załączniki do %1$s</string>
<string name="settings_notifications_auto_download_never">Nigdy nie pobieraj niczego automatycznie</string>
<string name="settings_notifications_auto_download_always">Automatycznie pobieraj wszystko</string>
<string name="settings_notifications_auto_download_100k">Jeśli poniżej 100 kB</string>
<string name="settings_notifications_auto_download_1m">Jeśli poniżej 1 MB</string>
<string name="settings_notifications_auto_download_10m">Jeśli poniżej 10 MB</string>
<string name="settings_notifications_auto_download_50m">Jeśli poniżej 50 MB</string>
<string name="settings_notifications_channel_prefs_summary">Zastąpić DND (nie przeszkadzać), dźwięki itp.</string>
<string name="settings_notifications_auto_delete_summary_one_month">Automatycznie usuń powiadomienia po miesiącu</string>
<string name="settings_notifications_auto_delete_never">Nigdy</string>
<string name="settings_notifications_auto_delete_one_day">Po jednym dniu</string>
<string name="settings_notifications_auto_delete_three_days">Po 3 dniach</string>
<string name="settings_notifications_auto_delete_one_week">Po tygodniu</string>
<string name="settings_notifications_auto_delete_three_months">Po 3 miesiącach</string>
<string name="settings_general_header">Ogólne</string>
<string name="settings_general_default_base_url_default_summary">%1$s (domyślny)</string>
<string name="settings_general_users_title">Zarządzaj użytkownikami</string>
<string name="settings_general_users_summary">Dodaj/usuń użytkowników dla tematów chronionych</string>
<string name="settings_general_users_prefs_user_used_by_many">Używane przez tematy %1$s</string>
<string name="settings_general_users_prefs_user_add">Dodaj użytkowników</string>
<string name="settings_general_users_prefs_user_add_title">Dodaj nowego użytkownika</string>
<string name="settings_general_users_prefs_user_add_summary">Stwórz nowego użytkownika dla nowego serwera</string>
<string name="settings_general_dark_mode_summary_system">Używanie domyślnych ustawień systemu</string>
<string name="settings_general_dark_mode_summary_dark">Tryb ciemny włączony. Jesteś wampirem\?</string>
<string name="settings_backup_restore_backup_title">Kopia zapasowa do pliku</string>
<string name="settings_backup_restore_backup_entry_everything">Wszystko</string>
<string name="settings_backup_restore_backup_entry_everything_no_users">Wszystko, z wyjątkiem użytkowników</string>
<string name="settings_backup_restore_backup_entry_settings_only">Tylko ustawienia</string>
<string name="settings_backup_restore_backup_successful">Kopia zapasowa utworzona</string>
<string name="settings_backup_restore_backup_failed">Kopia zapasowa nie powiodła się: %1$s</string>
<string name="settings_backup_restore_restore_title">Przywróc z pliku</string>
<string name="settings_backup_restore_restore_summary">Importuj konfigurację, powiadomienia i użytkowników</string>
<string name="settings_backup_restore_restore_successful">Przywrócono pomyślnie</string>
<string name="settings_advanced_header">Zaawansowane</string>
<string name="settings_advanced_broadcast_title">Roześlij wiadomości</string>
<string name="settings_advanced_record_logs_summary_enabled">Rejestrowanie (do 1000 wpisów) do urządzenia …</string>
<string name="settings_advanced_export_logs_entry_upload_original">Prześlij i kopiuj łącze</string>
<string name="settings_advanced_record_logs_title">Zapisz logi</string>
<string name="settings_advanced_export_logs_title">Kopiuj/wyślij logi</string>
<string name="settings_advanced_export_logs_copied_logs">Logi skopiowane do schowka</string>
<string name="settings_advanced_export_logs_uploading">Przesyłanie logów …</string>
<string name="settings_advanced_export_logs_copied_url">Logi przesłane i URL skopiowane</string>
<string name="settings_general_default_base_url_message">Wpisz tutaj główny adres URL swojego serwera, aby używać go jako domyślnego podczas subskrybowania nowych tematów i/lub udostępniania.</string>
<string name="user_dialog_title_add">Dodaj użytkownika</string>
<string name="settings_advanced_export_logs_scrub_dialog_empty">Żadne tematy/nazwy hostów nie zostały zredagowane. Może nie masz żadnych subskrypcji\?</string>
<string name="settings_advanced_export_logs_scrub_dialog_button_ok">OK</string>
<string name="settings_advanced_clear_logs_summary">Usuń poprzednio zarejestrowane logi i zacznij od nowa</string>
<string name="settings_advanced_export_logs_error_uploading">Przesyłanie logów nie powiodło się: %1$s</string>
<string name="detail_settings_notifications_instant_title">Natychmiastowe dostarczanie</string>
<string name="settings_advanced_connection_protocol_title">Protokół połączenia</string>
<string name="settings_advanced_connection_protocol_entry_jsonhttp">Strumień JSON przez HTTP</string>
<string name="settings_about_version_title">Wersja</string>
<string name="settings_about_version_format">ntfy %1$s (%2$s)</string>
<string name="settings_about_version_copied_to_clipboard_message">Skopiowano do schowka</string>
<string name="detail_settings_notifications_instant_summary_on">Powiadomienia są dostarczane natychmiastowo. Wymaga usługi pierwszego planu i zużywa więcej baterii.</string>
<string name="detail_settings_appearance_header">Wygląd</string>
<string name="detail_settings_appearance_icon_set_title">Ikona subskrypcji</string>
<string name="detail_settings_appearance_icon_set_summary">Wybierz ikonę, która ma być wyświetlana w powiadomieniach</string>
<string name="detail_settings_appearance_icon_remove_title">Ikona subskrypcji (dotknij, aby usunąć)</string>
<string name="detail_settings_appearance_icon_remove_summary">Ikona wyświetlana w powiadomieniach dla tego tematu</string>
<string name="detail_settings_appearance_icon_error_saving">Nie można zapisać ikony: %1$s</string>
<string name="main_banner_websocket_text">Przełączanie do WebSockets jest zalecanym sposobem łączenia się z Twoim serwerem, i może poprawić żywotność baterii, ale może wymagać <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">dodatkowej konfiguracji w proxy</a>. To może być przełączane w ustawieniach.</string>
<string name="main_banner_websocket_button_remind_later">Zapytaj później</string>
<string name="main_banner_websocket_button_dismiss">Odrzuć</string>
<string name="main_banner_websocket_button_enable_now">Aktywuj teraz</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Użyj strumienia JSON przez HTTP, aby połączyć się z serwerem. Ta metoda jest sprawdzona, ale może zużywać więcej baterii.</string>
<string name="main_menu_donate_title">Wspomóż💸</string>
<string name="detail_item_cannot_open_apk">Aplikacja nie może zostać zainstalowana. Pobierz ją poprzez przeglądarkę. Sprawdź problem #531 po więcej informacji.</string>
<string name="settings_notifications_insistent_max_priority_title">Nadal wysyłaj powiadomienia dla najwyższych priorytetów</string>
<string name="detail_settings_notifications_dedicated_channels_title">Własne ustawienia powiadomień</string>
<string name="detail_settings_notifications_dedicated_channels_summary_on">Używa własnych ustawień dla tej subskrypcji</string>
<string name="detail_settings_notifications_open_channels_title">Skonfiguruj ustawienia powiadomień</string>
<string name="detail_settings_notifications_open_channels_summary">Nadpisanie trybu nie przeszkadzać, dźwięki, itp.</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_enabled">Cały czas alarmuj</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_disabled">Wyślij alarm tylko raz</string>
<string name="channel_notifications_group_default_name">Domyślne</string>
<string name="settings_advanced_unifiedpush_title">Załącz</string>
<string name="settings_notifications_insistent_max_priority_summary_enabled">Powiadomienia o najwyższym priorytecie wysyłają alarm do czasu ich potwierdzenia</string>
<string name="settings_notifications_insistent_max_priority_summary_disabled">Powiadomienia o najwyższym priorytecie wysyłają powiadomienie tylko raz</string>
<string name="settings_advanced_unifiedpush_summary_enabled">Ntfy będzie działać jako dystrybutor UnifiedPush</string>
<string name="settings_advanced_unifiedpush_summary_disabled">Ntfy nie będzie dystrybutorem UnifiedPush</string>
<string name="detail_settings_notifications_dedicated_channels_summary_off">Używa domyślnych ustawień (dźwięki, nadpisanie trybu nie przeszkadzać, itp.)</string>
<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_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>
</resources>

View file

@ -4,14 +4,14 @@
<string name="detail_menu_test">Enviar notificação de teste</string>
<string name="detail_menu_copy_url">Copiar endereço do tema</string>
<string name="notification_dialog_show_all">Mostrar todas notificações</string>
<string name="channel_subscriber_notification_instant_text_three">Inscrito em três tópicos de entrega instantânea</string>
<string name="channel_subscriber_notification_instant_text_four">Inscrito em quatro tópicos de entrega instantânea</string>
<string name="channel_subscriber_notification_instant_text_three">Inscrito em três temas de entrega instantânea</string>
<string name="channel_subscriber_notification_instant_text_four">Inscrito em quatro temas de entrega instantânea</string>
<string name="channel_notifications_default_name">Notificações (prioridade padrão)</string>
<string name="channel_notifications_min_name">Notificações (prioridade mínima)</string>
<string name="main_menu_notifications_enabled">Notificações ativadas</string>
<string name="main_menu_settings_title">Configurações</string>
<string name="channel_subscriber_notification_noinstant_text">Inscrito em tópicos</string>
<string name="channel_subscriber_notification_noinstant_text_three">Inscrito em três tópicos</string>
<string name="channel_subscriber_notification_noinstant_text">Inscrito em temas</string>
<string name="channel_subscriber_notification_noinstant_text_three">Inscrito em três temas</string>
<string name="main_menu_report_bug_title">Relatar um problema</string>
<string name="main_item_status_reconnecting">Reconectando …</string>
<string name="channel_notifications_high_name">Notificações (prioridade alta)</string>
@ -19,35 +19,36 @@
<string name="channel_subscriber_service_name">Serviço de Assinatura</string>
<string name="channel_subscriber_notification_title">Aguardando notificações</string>
<string name="channel_subscriber_notification_instant_text">Inscrito em temas de entrega instantânea</string>
<string name="channel_subscriber_notification_instant_text_one">Inscrito em um tópico de entrega instantânea</string>
<string name="channel_subscriber_notification_instant_text_more">Inscrito em %1$d tópicos de entrega instantânea</string>
<string name="channel_subscriber_notification_noinstant_text_two">Inscrito em dois tópicos</string>
<string name="channel_subscriber_notification_noinstant_text_four">Inscrito em quatro tópicos</string>
<string name="channel_subscriber_notification_noinstant_text_more">Inscrito em %1$d tópicos</string>
<string name="refresh_message_result">%1$d notificação(ões) recebida(s)</string>
<string name="channel_subscriber_notification_instant_text_one">Inscrito em um tema de entrega instantânea</string>
<string name="channel_subscriber_notification_instant_text_more">Inscrito em %1$d temas de entrega instantânea</string>
<string name="channel_subscriber_notification_noinstant_text_two">Inscrito em dois temas</string>
<string name="channel_subscriber_notification_noinstant_text_four">Inscrito em quatro temas</string>
<string name="channel_subscriber_notification_noinstant_text_more">Inscrito em %1$d temas</string>
<string name="refresh_message_result">%1$d notificações recebidas</string>
<string name="refresh_message_no_results">Tudo está atualizado</string>
<string name="refresh_message_error">Não foi possível atualizar %1$d subscrições
<string name="refresh_message_error">Não foi possível atualizar %1$d inscrições
\n
\n%2$s</string>
<string name="main_action_bar_title">Temas inscritos</string>
<string name="main_menu_notifications_disabled_until">Notificações silenciadas até %1$s</string>
<string name="main_menu_notifications_disabled_until">Notificações pausadas até %1$s</string>
<string name="main_menu_rate_title">Avalie o aplicativo ⭐</string>
<string name="main_action_mode_delete_dialog_message">Cancelar inscrição dos tópicos selecionados e remover permanentemente todas notificações\?</string>
<string name="main_action_mode_delete_dialog_message">Cancelar inscrição dos temas selecionados e remover permanentemente todas notificações\?</string>
<string name="main_action_mode_delete_dialog_permanently_delete">Remover permanentemente</string>
<string name="main_action_mode_delete_dialog_cancel">Cancelar</string>
<string name="main_item_date_yesterday">ontem</string>
<string name="main_add_button_description">Adicionar Subscrição</string>
<string name="main_add_button_description">Inscrever-se</string>
<string name="main_no_subscriptions_text">Parece que você não tem nenhuma inscrição ainda.</string>
<string name="main_how_to_link">Instruções detalhadas disponíveis em ntfy.sh, e na documentação.</string>
<string name="main_banner_battery_text">O modo Economia de Energia deve estar desligado para evitar problemas de entrega de notificação no aplicativo.</string>
<string name="main_item_status_unified_push">%1$s(UnifiedPush)</string>
<string name="main_banner_websocket_button_remind_later">Perguntar depois</string>
<string name="main_banner_websocket_button_dismiss">Dispensar</string>
<string name="add_dialog_title">Inscrever-se no tópico</string>
<string name="add_dialog_description_below">Os tópicos podem não ser protegidos por senha, escolha um nome difícil de adivinhar. Uma vez inscrito, você pode usar as notificações PUT/POST.</string>
<string name="add_dialog_topic_name_hint">Nome do tópico, ex: alertas_jose</string>
<string name="main_banner_battery_text">Otimização de bateria deve estar desligada para evitar problemas de entrega de notificação no aplicativo.</string>
<string name="main_item_status_unified_push">%1$s (UnifiedPush)</string>
<string name="main_banner_json_stream_button_remind_later">Perguntar depois</string>
<string name="main_banner_json_stream_button_dismiss">Dispensar</string>
<string name="main_banner_json_stream_button_learn_more">Saiba mais</string>
<string name="add_dialog_title">Inscrever-se no tema</string>
<string name="add_dialog_description_below">Temas podem não ser protegidos por senha, escolha um nome difícil de adivinhar. Uma vez inscrito, você pode usar as notificações PUT/POST.</string>
<string name="add_dialog_topic_name_hint">Nome do tema, ex: alertas_jose</string>
<string name="add_dialog_use_another_server">Usar outro servidor</string>
<string name="add_dialog_use_another_server_description">Insira as URLs do servidor abaixo para inscrever-se nos tópicos de outros servidores.</string>
<string name="add_dialog_use_another_server_description">Insira as URLs do servidor abaixo para inscrever-se nos temas de outros servidores.</string>
<string name="add_dialog_foreground_description">Entrega instantânea está sempre ligada para hosts, exceto %1$s.</string>
<string name="add_dialog_button_back">Voltar</string>
<string name="add_dialog_error_connection_failed">Conexão falhou: %1$s</string>
@ -55,9 +56,9 @@
<string name="add_dialog_login_username_hint">Nome de usuário</string>
<string name="add_dialog_login_error_not_authorized">Login falhou. Usuário %1$s não autorizado.</string>
<string name="add_dialog_login_new_user">Novo usuário</string>
<string name="detail_no_notifications_text">Você não recebeu nenhuma notificação desse tópico ainda.</string>
<string name="detail_no_notifications_text">Você não recebeu nenhuma notificação desse tema ainda.</string>
<string name="detail_how_to_example">Exemplo (usando curl): <br/><tt>$ curl -d \"Oi\" %1$s</tt></string>
<string name="detail_clear_dialog_message">Apagar todas as notificações desse tópico\?</string>
<string name="detail_clear_dialog_message">Apagar todas as notificações desse tema\?</string>
<string name="detail_clear_dialog_permanently_delete">Apagar permanentemente</string>
<string name="detail_delete_dialog_message">Cancelar inscrição desse tema e apagar todas as notificações recebidas\?</string>
<string name="detail_delete_dialog_cancel">Cancelar</string>
@ -76,7 +77,7 @@
<string name="detail_item_menu_copy_contents_copied">Notificação copiada para área de transferência</string>
<string name="detail_item_saved_successfully">\"%1$s\" salvo na pasta \"Downloads\"</string>
<string name="detail_item_cannot_download">Não foi possível abrir ou baixar o anexo. O link expirou e nenhum arquivo local foi encontrado.</string>
<string name="detail_item_cannot_open_url">Não foi possível abrir a URL: %1$s</string>
<string name="detail_item_cannot_open_click_url">Não foi possível abrir a URL: %1$s</string>
<string name="detail_item_cannot_save">Não foi possível salvar o anexo: %1$s</string>
<string name="detail_item_cannot_delete">Não foi possível remover o anexo: %1$s</string>
<string name="detail_item_download_failed">Não foi possível baixar o anexo: %1$s</string>
@ -85,8 +86,8 @@
<string name="detail_item_download_info_not_downloaded_expires_x">não baixado, expira em %1$s</string>
<string name="detail_item_download_info_deleted_expired">apagado, link expirou</string>
<string name="detail_item_download_info_download_failed_expired">download falhou, link expirou</string>
<string name="detail_menu_notifications_disabled_forever">Notificações silenciadas</string>
<string name="detail_menu_notifications_disabled_until">Notificações silenciadas até %1$s</string>
<string name="detail_menu_notifications_disabled_forever">Notificações pausadas</string>
<string name="detail_menu_notifications_disabled_until">Notificações pausadas até %1$s</string>
<string name="detail_menu_enable_instant">Habilitar entrega instantânea</string>
<string name="detail_menu_clear">Limpar todas notificações</string>
<string name="detail_menu_settings">Configurações de inscrição</string>
@ -110,7 +111,7 @@
<string name="share_successful">Mensagem publicada</string>
<string name="notification_dialog_cancel">Cancelar</string>
<string name="notification_dialog_save">Salvar</string>
<string name="notification_dialog_muted_forever_toast_message">Notificações silenciadas</string>
<string name="notification_dialog_muted_forever_toast_message">Notificações pausadas</string>
<string name="notification_dialog_30min">30 minutos</string>
<string name="notification_dialog_1h">1 hora</string>
<string name="notification_dialog_2h">2 horas</string>
@ -124,7 +125,7 @@
\n%3$s</string>
<string name="settings_title">Configurações</string>
<string name="settings_notifications_header">Notificações</string>
<string name="settings_notifications_muted_until_forever">Notificações silenciadas até serem retomadas</string>
<string name="settings_notifications_muted_until_forever">Notificações pausadas até serem retomadas</string>
<string name="settings_notifications_min_priority_title">Prioridade mínima</string>
<string name="settings_notifications_min_priority_summary_any">Mostrando todas notificações</string>
<string name="settings_notifications_min_priority_summary_x_or_higher">Mostrando notificações se a prioridade for %1$d (%2$s) ou maior</string>
@ -184,9 +185,9 @@
<string name="settings_advanced_clear_logs_title">Limpar logs</string>
<string name="settings_advanced_clear_logs_summary">Apagar logs registrados anteriormente e recomeçar</string>
<string name="settings_advanced_connection_protocol_title">Protocolo de conexão</string>
<string name="settings_advanced_connection_protocol_summary_ws">Usar WebSockets para se conectar ao servidor. Este é o método recomendado, mas pode exigir configurações adicionais no seu proxy.</string>
<string name="settings_advanced_connection_protocol_summary_ws">Usar WebSockets para conectar ao servidor. Isso irá se tornar o padrão em Junho de 2022.</string>
<string name="settings_advanced_connection_protocol_entry_jsonhttp">Stream JSON sobre HTTP</string>
<string name="settings_advanced_connection_protocol_entry_ws">Web Sockets</string>
<string name="settings_advanced_connection_protocol_entry_ws">WebSockets</string>
<string name="settings_about_header">Sobre</string>
<string name="settings_about_version_title">Versão</string>
<string name="settings_about_version_format">ntfy %1$s (%2$s)</string>
@ -199,29 +200,30 @@
<string name="user_dialog_button_cancel">Cancelar</string>
<string name="user_dialog_button_delete">Apagar usuário</string>
<string name="channel_notifications_low_name">Notificações (prioridade baixa)</string>
<string name="channel_subscriber_notification_instant_text_two">Inscrito em dois tópicos de entrega instantânea</string>
<string name="channel_subscriber_notification_instant_text_two">Inscrito em dois temas de entrega instantânea</string>
<string name="user_dialog_button_save">Salvar</string>
<string name="main_item_status_text_one">%1$d notificação</string>
<string name="channel_subscriber_notification_noinstant_text_one">Inscrito em um tópico</string>
<string name="main_menu_notifications_disabled_forever">Notificações silenciadas</string>
<string name="channel_subscriber_notification_noinstant_text_one">Inscrito em um tema</string>
<string name="main_menu_notifications_disabled_forever">Notificações pausadas</string>
<string name="refresh_message_error_one">Não foi possível atualizar a inscrição: %1$s</string>
<string name="main_menu_docs_title">Leia a documentação</string>
<string name="main_action_mode_menu_unsubscribe">Cancelar inscrição</string>
<string name="main_unified_push_toast">Essa inscrição é gerenciada por %1$s via UnifiedPush</string>
<string name="main_banner_json_stream_text">Altere para WebSockets em Configurações / \"Protocolo de conexão\" para garantir a comunicação com seu servidor hospedado ntfy após Junho de 2022.</string>
<string name="main_item_status_text_not_one">%1$d notificações</string>
<string name="main_how_to_intro">Clique no + para criar ou inscrever-se em um tópico. Em seguida você receberá notificações no seu dispositivo ao enviar mensagens via PUT ou POST.</string>
<string name="main_how_to_intro">Clique no + para criar ou inscrever-se em um tema. Você receberá notificações no seu dispositivo ao enviar mensagens via PUT ou POST.</string>
<string name="main_banner_battery_button_remind_later">Perguntar depois</string>
<string name="main_banner_battery_button_dismiss">Dispensar</string>
<string name="add_dialog_button_subscribe">Inscrever-se</string>
<string name="main_banner_battery_button_fix_now">Consertar agora</string>
<string name="add_dialog_instant_delivery">Entrega instantânea em modo descanso</string>
<string name="add_dialog_instant_delivery">Entrega instantânea em modo soneca</string>
<string name="add_dialog_button_cancel">Cancelar</string>
<string name="add_dialog_instant_delivery_description">Garante que as mensagens são entregues imediatamente, mesmo se o dispositivo estiver inativo.</string>
<string name="add_dialog_button_login">Entrar</string>
<string name="add_dialog_login_password_hint">Senha</string>
<string name="add_dialog_login_description">Este tópico requer login. Insira um nome de usuário e senha.</string>
<string name="add_dialog_login_description">Esse tema requer login. Insira um nome de usuário e senha.</string>
<string name="detail_item_snack_deleted">Notificação removida</string>
<string name="detail_how_to_intro">Para enviar notificações para esse tópico, basta usar os métodos PUT ou POST na URL do tema.</string>
<string name="detail_how_to_intro">Para enviar notificações para esse tema, basta usar os métodos PUT ou POST na URL do tema.</string>
<string name="detail_how_to_link">Instruções detalhadas disponíveis em ntfy.sh e na documentação.</string>
<string name="detail_clear_dialog_cancel">Cancelar</string>
<string name="detail_delete_dialog_permanently_delete">Apagar permanentemente</string>
@ -246,25 +248,25 @@
<string name="settings_advanced_export_logs_scrub_dialog_empty">Nenhum tema/hostname foram censurados. Talvez você não tenha inscrições\?</string>
<string name="settings_advanced_clear_logs_deleted_toast">Logs apagados</string>
<string name="settings_advanced_export_logs_entry_copy_original">Copiar para área de transferência</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Usar um stream JSON via HTTP para conectar ao servidor. Esse método já funciona bem mas pode consumir mais bateria.</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Usar uma stream JSON sobre HTTP para conectar ao servidor. Esse método foi descontinuado e será removido em Junho de 2022.</string>
<string name="user_dialog_description_add">Você pode adicionar um usuário aqui. Todos os temas para esse servidor usarão esse usuário.</string>
<string name="user_dialog_username_hint">Nome de usuário</string>
<string name="user_dialog_password_hint_edit">Senha (não será modificado se deixado em branco)</string>
<string name="settings_advanced_export_logs_scrub_dialog_button_ok">OK</string>
<string name="notification_dialog_title">Silenciar notificações</string>
<string name="notification_dialog_title">Pausar notificações</string>
<string name="notification_dialog_enabled_toast_message">Notificações retomadas</string>
<string name="notification_dialog_muted_until_toast_message">Notificações silenciadas até %1$s</string>
<string name="notification_dialog_muted_until_toast_message">Notificações pausadas até %1$s</string>
<string name="notification_dialog_8h">8 horas</string>
<string name="notification_dialog_tomorrow">Até amanhã</string>
<string name="notification_popup_action_cancel">Cancelar</string>
<string name="notification_popup_file_download_successful">%1$s
\nArquivo: %2$s, baixado</string>
<string name="settings_notifications_muted_until_x">Notificações silenciadas até %1$s</string>
<string name="settings_notifications_muted_until_x">Notificações pausadas até %1$s</string>
<string name="notification_popup_file_download_failed">%1$s
\nArquivo: %2$s, download falhou</string>
<string name="settings_notifications_muted_until_show_all">Mostrando todas notificações</string>
<string name="settings_notifications_min_priority_summary_max">Mostrando notificações se a prioridade for 5 (máximo)</string>
<string name="settings_notifications_muted_until_title">Silenciar notificações</string>
<string name="settings_notifications_muted_until_title">Pausar notificações</string>
<string name="settings_notifications_min_priority_min">Qualquer prioridade</string>
<string name="settings_notifications_min_priority_high">Prioridade alta ou maior</string>
<string name="settings_notifications_min_priority_max">Somente prioridade máxima</string>
@ -293,54 +295,4 @@
<string name="settings_advanced_header">Avançado</string>
<string name="settings_advanced_broadcast_summary_disabled">Aplicativos não podem receber notificações como transmissão</string>
<string name="settings_advanced_record_logs_summary_enabled">Registrando (até 1000 registros) para o dispositivo …</string>
<string name="detail_deep_link_subscribed_toast_message">Inscrito no tópico %1$s</string>
<string name="settings_notifications_priority_high">alta</string>
<string name="notification_popup_user_action_failed">%1$s falhou: %2$s</string>
<string name="settings_notifications_channel_prefs_title">Configurações do canal</string>
<string name="settings_notifications_priority_max">máxima</string>
<string name="settings_notifications_priority_min">mínimo</string>
<string name="settings_notifications_priority_default">padrão</string>
<string name="settings_notifications_priority_low">baixa</string>
<string name="settings_notifications_channel_prefs_summary">Modo Não Perturbe, sons, etc.</string>
<string name="detail_settings_notifications_instant_title">Entrega instantânea</string>
<string name="detail_settings_notifications_instant_summary_on">Notificações são entregues instantaneamente. Requer um serviço em primeiro plano e consome mais bateria.</string>
<string name="detail_settings_notifications_instant_summary_off">Notificações são entregues usando Firebase. A entrega pode demorar, mas consome menos bateria.</string>
<string name="detail_settings_appearance_header">Aparência</string>
<string name="detail_settings_appearance_icon_set_title">Ícone de inscrição</string>
<string name="detail_settings_appearance_icon_set_summary">Definir um ícone a ser exibido nas notificações</string>
<string name="detail_settings_appearance_icon_remove_title">Ícone de inscrição (toque para remover)</string>
<string name="detail_settings_appearance_icon_remove_summary">Ícone exibido em notificações para este tópico</string>
<string name="detail_settings_global_setting_title">Usar configurações globais</string>
<string name="channel_subscriber_notification_instant_text_five">Inscrito em cinco tópicos de entrega instantânea</string>
<string name="channel_subscriber_notification_noinstant_text_six">Inscrito em seis tópicos</string>
<string name="detail_settings_appearance_icon_error_saving">Não foi possível salvar o ícone: %1$s</string>
<string name="channel_subscriber_notification_instant_text_six">Inscrito em seis tópicos de entrega instantânea</string>
<string name="channel_subscriber_notification_noinstant_text_five">Inscrito em cinco tópicos</string>
<string name="detail_settings_global_setting_suffix">usando configurações globais</string>
<string name="detail_settings_appearance_display_name_title">Nome de exibição</string>
<string name="detail_settings_appearance_display_name_default_summary">%1$s (padrão)</string>
<string name="detail_settings_appearance_display_name_message">Defina um nome personalizado para esta inscrição. Deixe em branco para padrão (%1$s).</string>
<string name="main_banner_websocket_text">Mudar para WebSockets é o modo recomendado de conectar ao seu servidor, e pode melhorar a vida da bateria, mas pode necessitar de <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">configurações adicionais no seu proxy</a>. Isso pode ser habilitado nas Configurações.</string>
<string name="detail_settings_about_header">Sobre</string>
<string name="detail_settings_about_topic_url_title">URL do tópico</string>
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">Copiado para área de transferência</string>
<string name="add_dialog_base_urls_dropdown_choose">Escolha o URL do serviço</string>
<string name="add_dialog_base_urls_dropdown_clear">Limpar o URL do serviço</string>
<string name="main_banner_websocket_button_enable_now">Habilitar agora</string>
<string name="channel_notifications_group_default_name">Padrão</string>
<string name="main_menu_donate_title">Doar 💸</string>
<string name="settings_notifications_insistent_max_priority_summary_disabled">Notificações de prioridade máxima alertam apenas uma vez</string>
<string name="detail_settings_notifications_open_channels_title">Definir configurações de notificação</string>
<string name="detail_settings_notifications_open_channels_summary">Sobrepor Não Perturbe (DND), sons, etc.</string>
<string name="settings_advanced_unifiedpush_summary_disabled">ntfy não atuará como distribuidor UnifiedPush</string>
<string name="detail_settings_notifications_dedicated_channels_title">Configurações de notificação personalizadas</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_disabled">Alertar apenas uma vez</string>
<string name="detail_settings_notifications_dedicated_channels_summary_on">Usando configurações personalizadas para esta assinatura</string>
<string name="detail_settings_notifications_dedicated_channels_summary_off">Usando configurações padrão (sons, substituição de Não perturbe, etc.)</string>
<string name="detail_item_cannot_open_apk">Apps não podem mais ser instalados, baixe pelo navegador. Veja a issue #531 para detalhes.</string>
<string name="settings_notifications_insistent_max_priority_title">Continue alertando para a prioridade mais alta</string>
<string name="settings_notifications_insistent_max_priority_summary_enabled">Notificações de prioridade máxima alertam continuamente até serem dispensadas</string>
<string name="settings_advanced_unifiedpush_title">Habilitar UnifiedPush</string>
<string name="settings_advanced_unifiedpush_summary_enabled">ntfy vai agir como um distribuidor UnifiedPush</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_enabled">Continuar alertando</string>
</resources>

View file

@ -1,343 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="channel_subscriber_notification_instant_text_three">Três tópicos de entrega instantânea subscritos</string>
<string name="channel_subscriber_notification_instant_text_four">Quatro tópicos de entrega instantânea subscritos</string>
<string name="channel_subscriber_notification_instant_text_five">Cinco tópicos de entrega instantânea subscritos</string>
<string name="channel_subscriber_notification_instant_text_six">Seis tópicos de entrega instantânea subscritos</string>
<string name="channel_subscriber_notification_instant_text_more">%1$d tópico(s) de entrega instantânea subscrito(s)</string>
<string name="channel_subscriber_notification_noinstant_text">Tópicos subscritos</string>
<string name="channel_subscriber_notification_noinstant_text_one">Um tópico subscrito</string>
<string name="channel_subscriber_notification_noinstant_text_two">Dois tópicos subscritos</string>
<string name="channel_subscriber_notification_noinstant_text_three">Três tópicos subscritos</string>
<string name="channel_subscriber_notification_noinstant_text_six">Seis tópicos subscritos</string>
<string name="channel_subscriber_notification_noinstant_text_more">%1$d tópico(s) subscrito(s)</string>
<string name="refresh_message_result">%1$d notificação(ões) recebida(s)</string>
<string name="refresh_message_no_results">Está tudo atualizado</string>
<string name="refresh_message_error">Não foi possível atualizar %1$d subscrição(ões)
\n
\n%2$s</string>
<string name="refresh_message_error_one">Não foi possível atualizar a subscrição: %1$s</string>
<string name="main_action_bar_title">Tópicos subscritos</string>
<string name="main_menu_notifications_enabled">Notificações ativadas</string>
<string name="main_menu_notifications_disabled_forever">Notificações silenciadas</string>
<string name="channel_notifications_min_name">Prioridade mínima</string>
<string name="channel_notifications_low_name">Prioridade baixa</string>
<string name="channel_subscriber_service_name">Serviço de subscrição</string>
<string name="channel_subscriber_notification_title">À escuta de novas notificações</string>
<string name="channel_subscriber_notification_instant_text">Tópicos de entrega instantânea subscritos</string>
<string name="main_menu_notifications_disabled_until">Notificações silenciadas até %1$s</string>
<string name="main_menu_settings_title">Configurações</string>
<string name="main_menu_report_bug_title">Reportar um problema</string>
<string name="main_menu_docs_title">Ler a documentação</string>
<string name="main_menu_rate_title">Avaliar a aplicação ⭐</string>
<string name="main_action_mode_menu_unsubscribe">Cancelar subscrição</string>
<string name="main_action_mode_delete_dialog_message">Cancelar a subscrição do(s) tópico(s) selecionado(s) e eliminar permanentemente todas as notificações\?</string>
<string name="main_action_mode_delete_dialog_permanently_delete">Eliminar permanentemente</string>
<string name="main_action_mode_delete_dialog_cancel">Cancelar</string>
<string name="main_item_status_text_one">%1$d notificação</string>
<string name="main_item_status_text_not_one">%1$d notificações</string>
<string name="main_item_status_reconnecting">A restabelecer ligação …</string>
<string name="main_item_date_yesterday">ontem</string>
<string name="main_add_button_description">Adicionar subscrição</string>
<string name="main_no_subscriptions_text">Parece que ainda não tem subscrições.</string>
<string name="main_how_to_link">Instruções detalhadas disponíveis em ntfy.sh, e na documentação.</string>
<string name="main_unified_push_toast">Esta subscrição é controlada por %1$s via UnifiedPush</string>
<string name="main_banner_battery_text">A otimização de bateria deve estar desativada para a aplicação, de modo a evitar problemas na receção de notificações.</string>
<string name="main_banner_battery_button_remind_later">Perguntar depois</string>
<string name="main_banner_battery_button_dismiss">Dispensar</string>
<string name="main_banner_battery_button_fix_now">Corrigir agora</string>
<string name="main_banner_websocket_button_remind_later">Perguntar depois</string>
<string name="add_dialog_title">Subscrever tópico</string>
<string name="add_dialog_topic_name_hint">Nome do tópico, por exemplo: \"alertas_do_filipe\"</string>
<string name="channel_subscriber_notification_noinstant_text_four">Quatro tópicos subscritos</string>
<string name="channel_subscriber_notification_noinstant_text_five">Cinco tópicos subscritos</string>
<string name="main_how_to_intro">Clique no + para subscrever um tópico. Depois, receberá notificações no seu dispositivo quando enviar mensagens via PUT ou POST.</string>
<string name="channel_notifications_max_name">Prioridade máxima</string>
<string name="main_banner_websocket_text">Trocar para WebSockets é a forma recomendada de se ligar ao seu servidor, podendo melhorar a duração da bateria, mas pode necessitar <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">configurações adicionais no seu \"proxy\"</a>. Isto pode ser alterado nas Configurações.</string>
<string name="main_banner_websocket_button_dismiss">Dispensar</string>
<string name="channel_notifications_default_name">Prioridade padrão</string>
<string name="channel_notifications_high_name">Prioridade alta</string>
<string name="channel_subscriber_notification_instant_text_one">Um tópico de entrega instantânea subscrito</string>
<string name="main_banner_websocket_button_enable_now">Ativar agora</string>
<string name="channel_subscriber_notification_instant_text_two">Dois tópicos de entrega instantânea subscritos</string>
<string name="add_dialog_description_below">Tópicos podem não ser protegidos por palavra-passe, portanto escolha um nome que seja difícil de adivinhar. Uma vez inscrito, poderá enviar notificações PUT/POST.</string>
<string name="main_item_status_unified_push">%1$s (UnifiedPush)</string>
<string name="add_dialog_use_another_server">Utilizar outro servidor</string>
<string name="add_dialog_button_login">Entrar</string>
<string name="add_dialog_login_title">Autenticação necessária</string>
<string name="detail_clear_dialog_message">Deseja eliminar todas as notificações nesse tópico\?</string>
<string name="detail_clear_dialog_permanently_delete">Eliminar permanentemente</string>
<string name="detail_delete_dialog_permanently_delete">Eliminar permanentemente</string>
<string name="detail_delete_dialog_cancel">Cancelar</string>
<string name="detail_test_title">Teste: Pode definir um título se quiser.</string>
<string name="detail_test_message_error">Não foi possível enviar a mensagem: %1$s</string>
<string name="detail_test_message_error_unauthorized_anon">Não foi possível enviar a mensagem: Publicações anónimas não são permitidas.</string>
<string name="detail_copied_to_clipboard_message">Copiado para a área de transferência</string>
<string name="detail_deep_link_subscribed_toast_message">Tópico \"%1$s\" subscrito</string>
<string name="detail_item_tags">Etiquetas: %1$s</string>
<string name="detail_item_snack_deleted">Notificação eliminada</string>
<string name="detail_item_snack_undo">Desfazer</string>
<string name="detail_item_menu_download">Descarregar ficheiro</string>
<string name="detail_item_menu_cancel">Cancelar a descarga</string>
<string name="detail_item_cannot_open">Não foi possível abrir o anexo: %1$s</string>
<string name="detail_item_cannot_open_not_found">Não foi possível abrir o anexo: O ficheiro pode ter sido eliminado, ou não existe nenhuma aplicação instalada que o consiga abrir.</string>
<string name="detail_item_cannot_open_url">Não foi possível abrir o URL: %1$s</string>
<string name="detail_item_cannot_save">Não foi possível guardar o anexo: %1$s</string>
<string name="detail_item_cannot_delete">Não foi possível eliminar o anexo: %1$s</string>
<string name="detail_item_download_failed">Não foi possível descarregar o anexo: %1$s</string>
<string name="detail_item_download_info_not_downloaded_expires_x">não foi decarregado, expira em %1$s</string>
<string name="detail_item_download_info_downloading_x_percent">%1$d%% decarregado</string>
<string name="detail_item_download_info_deleted">eliminado</string>
<string name="detail_item_download_info_deleted_expired">eliminado, a ligação expirou</string>
<string name="detail_item_download_info_deleted_expires_x">eliminado, a ligação expira em %1$s</string>
<string name="detail_item_download_info_download_failed">falha ao descarregar</string>
<string name="detail_item_download_info_download_failed_expired">falha ao descarregar, a ligação expirou</string>
<string name="detail_item_download_info_download_failed_expires_x">falha ao descarregar, a ligação expira em %1$s</string>
<string name="detail_menu_notifications_enabled">Notificações atvadas</string>
<string name="detail_menu_notifications_disabled_forever">Notificações silenciadas</string>
<string name="detail_menu_enable_instant">Ativar a entrega instantânea</string>
<string name="detail_menu_disable_instant">Desativar a entrega instantânea</string>
<string name="detail_menu_test">Enviar uma notificação de teste</string>
<string name="detail_menu_copy_url">Copiar o endereço do tópico</string>
<string name="detail_menu_clear">Limpar todas as notificações</string>
<string name="detail_menu_settings">Configurações das subscrições</string>
<string name="detail_menu_unsubscribe">Anular subscrição</string>
<string name="detail_action_mode_menu_delete">Eliminar</string>
<string name="detail_action_mode_delete_dialog_message">Deseja eliminar permanentemente a(s) notificação(ões) selecionada(s)\?</string>
<string name="detail_action_mode_delete_dialog_permanently_delete">Eliminar permanentemente</string>
<string name="detail_action_mode_delete_dialog_cancel">Cancelar</string>
<string name="detail_settings_title">Configurações das subscrições</string>
<string name="share_title">Partilhar</string>
<string name="share_menu_send">Partilhar</string>
<string name="share_content_title">Pré-visualização da mensagem</string>
<string name="share_content_image_text">Uma imagem foi partilhada consigo</string>
<string name="share_topic_title">Partilhar para</string>
<string name="share_suggested_topics">Tópicos sugeridos</string>
<string name="share_successful">Mensagem publicada</string>
<string name="notification_dialog_cancel">Cancelar</string>
<string name="notification_dialog_save">Guardar</string>
<string name="notification_dialog_enabled_toast_message">Notificações retomadas</string>
<string name="notification_dialog_muted_until_toast_message">Notificações silenciadas até %1$s</string>
<string name="notification_dialog_show_all">Mostrar todas as notificações</string>
<string name="notification_dialog_2h">2 horas</string>
<string name="notification_dialog_8h">8 horas</string>
<string name="notification_dialog_tomorrow">Até amanhã</string>
<string name="notification_dialog_forever">Até serem retomadas</string>
<string name="notification_popup_action_browse">Navegar</string>
<string name="notification_popup_action_download">Descarregar</string>
<string name="notification_popup_action_cancel">Cancelar</string>
<string name="notification_popup_file">%1$s
\nFicheiro: %2$s</string>
<string name="notification_popup_file_downloading">A descarregar %1$s, %2$d%%
\n%3$s</string>
<string name="notification_popup_file_download_successful">%1$s
\nFicheiro: %2$s, descarregado</string>
<string name="notification_popup_file_download_failed">%1$s
\nFicheiro: %2$s, falha ao descarregar</string>
<string name="notification_popup_user_action_failed">%1$s falhou: %2$s</string>
<string name="settings_title">Configurações</string>
<string name="settings_notifications_header">Notificações</string>
<string name="settings_notifications_muted_until_title">Silenciar as notificações</string>
<string name="settings_notifications_muted_until_show_all">A mostrar todas as notificações</string>
<string name="settings_notifications_muted_until_forever">Notificações silenciadas até serem retomadas</string>
<string name="settings_notifications_muted_until_x">Notificações silenciadas até %1$s</string>
<string name="settings_notifications_min_priority_title">Prioridade mínima</string>
<string name="settings_notifications_min_priority_summary_any">A mostrar todas as notificações</string>
<string name="settings_notifications_min_priority_summary_x_or_higher">Mostrar notificações se a prioridade for %1$d (%2$s) ou superior</string>
<string name="settings_notifications_min_priority_summary_max">Mostrar notificações se a prioridade for 5 (máxima)</string>
<string name="settings_notifications_min_priority_min">Qualquer prioridade</string>
<string name="settings_notifications_min_priority_low">Prioridade baixa ou superior</string>
<string name="settings_notifications_min_priority_default">Prioridade padrão ou superior</string>
<string name="settings_notifications_min_priority_high">Prioridade alta ou superior</string>
<string name="settings_notifications_min_priority_max">Apenas prioridade máxima</string>
<string name="settings_notifications_priority_min">mínima</string>
<string name="settings_notifications_priority_low">baixa</string>
<string name="settings_notifications_priority_default">padrão</string>
<string name="settings_notifications_priority_high">alta</string>
<string name="settings_notifications_priority_max">máxima</string>
<string name="settings_notifications_channel_prefs_title">Configurações de canal</string>
<string name="settings_notifications_channel_prefs_summary">Sobrescrever modo \"Não incomodar\" (NI), sons, etc.</string>
<string name="settings_notifications_auto_download_title">Descarregar os anexos</string>
<string name="settings_notifications_auto_download_summary_always">Descarregar todos os anexos automaticamente</string>
<string name="settings_notifications_auto_download_summary_never">Nunca descarregar todos os anexos automaticamente</string>
<string name="settings_notifications_auto_download_summary_smaller_than_x">Descarregar os anexos automaticamente até %1$s</string>
<string name="settings_notifications_auto_download_never">Nunca descarregar nada automaticamente</string>
<string name="settings_notifications_auto_download_always">Descarregar tudo automaticamente</string>
<string name="settings_notifications_auto_download_100k">Se abaixo de 100kB</string>
<string name="settings_notifications_auto_download_500k">Se abaixo de 500 kB</string>
<string name="settings_notifications_auto_download_1m">Se abaixo de 1 MB</string>
<string name="settings_notifications_auto_delete_title">Elminar as notificações</string>
<string name="settings_notifications_auto_delete_summary_never">Nunca eliminar as notificações automaticamente</string>
<string name="settings_notifications_auto_delete_summary_one_day">Elminar as notificações automaticamente após um dia</string>
<string name="settings_notifications_auto_delete_summary_three_days">Eliminar as notificações automaticamente após 3 dias</string>
<string name="settings_notifications_auto_delete_summary_one_week">Eliminar as notificações automaticamente após uma semana</string>
<string name="settings_notifications_auto_delete_summary_one_month">Eliminar as notificações automaticamente após um mês</string>
<string name="settings_notifications_auto_delete_summary_three_months">Eliminar as notificações automaticamente após 3 meses</string>
<string name="settings_notifications_auto_delete_never">Nunca</string>
<string name="settings_notifications_auto_delete_one_day">Após um dia</string>
<string name="settings_notifications_auto_delete_three_days">Após 3 dias</string>
<string name="settings_notifications_auto_delete_one_week">Após uma semana</string>
<string name="settings_notifications_auto_delete_one_month">Após um mês</string>
<string name="settings_notifications_auto_delete_three_months">Após 3 meses</string>
<string name="settings_general_header">Geral</string>
<string name="settings_general_default_base_url_title">Servidor padrão</string>
<string name="settings_general_default_base_url_message">Insira o URL raíz do servidor para utilizar seu próprio como padrão ao subscrever novos tópicos e/ou partilhar em tópicos.</string>
<string name="settings_general_default_base_url_default_summary">%1$s (padrão)</string>
<string name="settings_general_users_title">Gerir utilizadores</string>
<string name="settings_general_users_summary">Adicionar/remover utilizadores em tópicos protegidos</string>
<string name="settings_general_users_prefs_title">Utilizadores</string>
<string name="settings_general_users_prefs_user_not_used">Não utilizado por nenhum tópico</string>
<string name="settings_general_users_prefs_user_used_by_one">Utilizado pelo tópico %1$s</string>
<string name="settings_general_users_prefs_user_used_by_many">Utilizado pelos tópicos %1$s</string>
<string name="settings_general_users_prefs_user_add">Adicionar utilizadores</string>
<string name="settings_general_users_prefs_user_add_title">Adicionar novo utilizador</string>
<string name="settings_general_users_prefs_user_add_summary">Crie um novo utilizador para um novo servidor</string>
<string name="settings_general_dark_mode_summary_dark">Modo escuro ligado. Por acaso é um vampiro\?</string>
<string name="settings_general_dark_mode_entry_system">Usar a predefinição do sistema</string>
<string name="settings_general_dark_mode_entry_light">Modo claro</string>
<string name="settings_general_dark_mode_entry_dark">Modo escuro</string>
<string name="settings_backup_restore_header">Cópias de segurança e restauro</string>
<string name="settings_backup_restore_backup_title">Fazer cópia de segurança para um ficheiro</string>
<string name="settings_backup_restore_backup_summary">Exportar as configurações, notificações e utilizadores</string>
<string name="settings_backup_restore_backup_entry_everything">Tudo</string>
<string name="settings_backup_restore_backup_entry_everything_no_users">Tudo, exceto os utilizadores</string>
<string name="settings_backup_restore_backup_entry_settings_only">Apenas as configurações</string>
<string name="settings_backup_restore_backup_successful">Cópia criada</string>
<string name="settings_backup_restore_backup_failed">Falha ao criar cópia: %1$s</string>
<string name="detail_item_saved_successfully">Guardado como \"%1$s\" na pasta \"Downloads\" (\"Transferências\")</string>
<string name="detail_item_menu_copy_contents_copied">Notificação copiada para a área de transferência</string>
<string name="detail_item_cannot_download">Não foi possível abrir ou descarregar o anexo. A ligação expirou e nenhum ficheiro local foi encontrado.</string>
<string name="detail_item_download_info_not_downloaded_expired">não foi descarregado, a ligação expirou</string>
<string name="detail_menu_notifications_disabled_until">Notificações silenciadas até %1$s</string>
<string name="share_content_image_error">Não foi possível ler a imagem: %1$s</string>
<string name="settings_notifications_auto_download_10m">Se abaixo de 10 MB</string>
<string name="add_dialog_foreground_description">A entrega instantânea está sempre ligada para \"hosts\" que não sejam %1$s.</string>
<string name="add_dialog_use_another_server_description">Insira os URLs de serviço abaixo para subscrever tópicos de outros servidores.</string>
<string name="add_dialog_button_cancel">Cancelar</string>
<string name="add_dialog_button_subscribe">Subscrever</string>
<string name="add_dialog_error_connection_failed">A ligação falhou: %1$s</string>
<string name="add_dialog_login_description">Esse tópico necessita autenticação. Por favor, insira um nome de utilizador e palavra-passe.</string>
<string name="add_dialog_login_new_user">Novo utilizador</string>
<string name="add_dialog_base_urls_dropdown_choose">Escolha URL de serviço</string>
<string name="detail_how_to_example">Exemplo (utilizando curl): <br/><tt>$ curl -d \"Olá\" %1$s</tt></string>
<string name="detail_delete_dialog_message">Deseja anular a subscrição deste tópico e eliminar todas as notificações recebidas\?</string>
<string name="detail_test_message">Esta é uma notificação de teste da aplicação Android do ntfy. Tem uma prioridade de nível %1$d. Se enviar outra notificação, poderá ser diferente.</string>
<string name="detail_test_message_error_too_large">Não foi possível enviar a mensagem: O anexo é grande demais.</string>
<string name="detail_instant_delivery_enabled">Entrega instantânea ativada</string>
<string name="detail_item_menu_open">Abrir ficheiro</string>
<string name="detail_item_menu_save_file">Guardar o ficheiro</string>
<string name="detail_item_menu_copy_url">Copiar URL</string>
<string name="detail_item_download_info_not_downloaded">não foi descarregado</string>
<string name="add_dialog_instant_delivery">Entrega instantânea em modo soneca</string>
<string name="add_dialog_instant_delivery_description">Garante que as mensagens são entregues imediatamente, mesmo que o dispositivo esteja inativo.</string>
<string name="add_dialog_button_back">Voltar</string>
<string name="add_dialog_login_username_hint">Nome de utilizador</string>
<string name="add_dialog_login_password_hint">Palavra-passe</string>
<string name="add_dialog_login_error_not_authorized">A autenticação falhou. O utilizador \"%1$s\" não foi autorizado.</string>
<string name="add_dialog_base_urls_dropdown_clear">Limpar URL de serviço</string>
<string name="detail_no_notifications_text">Ainda não recebeu nenhuma notificação neste tópico.</string>
<string name="detail_how_to_intro">Para enviar notificações deste tópico, simplesmente faça um pedido PUT ou POST para o URL do tópico.</string>
<string name="detail_how_to_link">Instruções detalhadas disponíveis em ntfy.sh, e na documentação.</string>
<string name="detail_clear_dialog_cancel">Cancelar</string>
<string name="detail_test_message_error_unauthorized_user">Não foi possível enviar a mensagem: O utilizador \"%1$s\" não está autorizado.</string>
<string name="detail_instant_delivery_disabled">Entrega instantânea desativada</string>
<string name="detail_item_menu_delete">Eliminar ficheiro</string>
<string name="detail_item_menu_copy_url_copied">URL copiado para a área de transferência</string>
<string name="detail_item_menu_copy_contents">Copiar notificação</string>
<string name="notification_dialog_30min">30 minutos</string>
<string name="notification_popup_action_open">Abrir</string>
<string name="detail_action_mode_menu_copy">Copiar</string>
<string name="share_content_text_hint">Adicione conteúdo a partilhar aqui</string>
<string name="share_content_file_error">Não foi possível ler as informações do ficheiro: %1$s</string>
<string name="notification_dialog_muted_forever_toast_message">Notificações silenciadas</string>
<string name="settings_notifications_auto_download_5m">Se abaixo de 5 MB</string>
<string name="share_content_file_text">Um ficheiro foi partilhado consigo</string>
<string name="notification_dialog_1h">1 hora</string>
<string name="settings_notifications_auto_download_50m">Se abaixo de 50 MB</string>
<string name="notification_dialog_title">Silenciar notificações</string>
<string name="settings_general_dark_mode_summary_light">Modo claro</string>
<string name="settings_general_dark_mode_title">Modo escuro</string>
<string name="settings_general_dark_mode_summary_system">Usar a predefinição do sistema</string>
<string name="main_menu_donate_title">Doar 💸</string>
<string name="settings_backup_restore_restore_failed">Falha ao restaurar %1$s</string>
<string name="settings_advanced_header">Avançado</string>
<string name="settings_advanced_broadcast_title">Messagens de transmissão</string>
<string name="settings_advanced_broadcast_summary_disabled">As aplicações não podem receber notificações como transmissões</string>
<string name="settings_advanced_broadcast_summary_enabled">As aplicações podem receber notificações como transmissões</string>
<string name="settings_advanced_export_logs_entry_copy_original">Copiar para área de transferência</string>
<string name="settings_advanced_export_logs_entry_copy_scrubbed">Copiar para área de transferência (censurado)</string>
<string name="settings_advanced_export_logs_entry_upload_original">Enviar e copiar ligação</string>
<string name="settings_advanced_export_logs_uploading">A enviar registos …</string>
<string name="settings_advanced_export_logs_copied_url">Registos enviados e URL copiado</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Utilizar uma \"stream\" de JSON através de HTTP para se ligar ao servidor. Este método foi bem testado na pratica, mas pode consumir mais bateria.</string>
<string name="settings_about_version_format">ntfy %1$s (%2$s)</string>
<string name="detail_settings_notifications_instant_summary_off">As notificações são entregues utilizando o Firebase. A entrega pode atrasar, mas consome menos bateria.</string>
<string name="detail_settings_appearance_header">Aparência</string>
<string name="detail_settings_appearance_icon_set_title">Ícone de subscrição</string>
<string name="detail_settings_appearance_icon_set_summary">Defina um ícone para ser exibido nas notificações</string>
<string name="detail_settings_appearance_icon_remove_title">Ícone de subscrição (toque para remover)</string>
<string name="detail_settings_appearance_display_name_message">Defina um nome de exibição personalizado para esta subscrição. Deixe em branco para o padrão (%1$s).</string>
<string name="detail_settings_appearance_display_name_default_summary">%1$s (padrão)</string>
<string name="detail_settings_global_setting_title">Usar configuração global</string>
<string name="detail_settings_global_setting_suffix">usar configuração global</string>
<string name="detail_settings_about_header">Sobre a aplicação</string>
<string name="detail_settings_about_topic_url_title">URL do tópico</string>
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">Copiado para a área de transferência</string>
<string name="user_dialog_title_add">Adicionar utilizador</string>
<string name="settings_backup_restore_restore_title">Restaurar de um ficheiro</string>
<string name="settings_backup_restore_restore_summary">Importar configurações, notificações e usuários</string>
<string name="settings_backup_restore_restore_successful">Restauração concluída</string>
<string name="settings_advanced_record_logs_summary_enabled">A registar (até 1000 entradas) no dispositivo …</string>
<string name="settings_advanced_record_logs_summary_disabled">Ative os registos para os poder partilhar mais tarde e diagnosticar problemas.</string>
<string name="settings_advanced_record_logs_title">Registos</string>
<string name="settings_advanced_export_logs_title">Copiar/enviar registos</string>
<string name="settings_advanced_export_logs_summary">Copie os registos para a área de transferência ou faça envie para nopaste.net (propriedade do autor do ntfy). \"Hostnames\" e tópicos podem ser censurados, as notificações não.</string>
<string name="settings_advanced_export_logs_entry_upload_scrubbed">Enviar e copiar ligação (censurado)</string>
<string name="settings_advanced_export_logs_copied_logs">Registos copiados para área de transferência</string>
<string name="settings_advanced_export_logs_scrub_dialog_text">Esses tópicos/\"hostnames\" foram substituídos por nomes de frutas, portanto pode partilhar os registos sem se preocupar:
\n
\n%1$s
\n
\nAs palavras-passe são retiradas e não são listadas aqui.</string>
<string name="settings_advanced_export_logs_error_uploading">Não foi possível enviar os registos: %1$s</string>
<string name="settings_advanced_export_logs_scrub_dialog_button_ok">OK</string>
<string name="settings_advanced_export_logs_scrub_dialog_empty">Nenhum tópico/\"hostname\" foi editado. Talvez não tenha nenhuma subscrição\?</string>
<string name="settings_advanced_clear_logs_title">Limpar registos</string>
<string name="settings_advanced_clear_logs_deleted_toast">Registos excluídos</string>
<string name="settings_advanced_connection_protocol_title">Protocolo de ligação</string>
<string name="settings_advanced_clear_logs_summary">Eliminar registos gravados anteriormente e começar de novo</string>
<string name="settings_advanced_connection_protocol_summary_ws">Utilizar WebSockets para se ligar ao servidor. Este é o método recomendado, mas pode exigir configuração adicional no seu proxy.</string>
<string name="settings_advanced_connection_protocol_entry_jsonhttp">\"Stream\" JSON através de HTTP</string>
<string name="settings_about_header">Sobre a aplicação</string>
<string name="settings_about_version_title">Versão</string>
<string name="settings_advanced_connection_protocol_entry_ws">WebSockets</string>
<string name="detail_settings_notifications_instant_title">Entrega instantânea</string>
<string name="detail_settings_notifications_instant_summary_on">As notificações são entregues instantaneamente. Requer um serviço que corre em primeiro plano e consome mais bateria.</string>
<string name="settings_about_version_copied_to_clipboard_message">Copiado para área de transferência</string>
<string name="detail_settings_appearance_icon_error_saving">Não foi possível guardar o ícone: %1$s</string>
<string name="detail_settings_appearance_icon_remove_summary">Ícone exibido nas notificações deste tópico</string>
<string name="detail_settings_appearance_display_name_title">Nome de exibição</string>
<string name="user_dialog_description_edit">Pode editar o nome/palavra-passe do utilizador selecionado ou eliminá-lo.</string>
<string name="user_dialog_base_url_hint">URL do serviço</string>
<string name="user_dialog_title_edit">Editar utilizador</string>
<string name="user_dialog_description_add">Pode adicionar um utilizador aqui. Todos os tópicos para o servidor fornecido usarão esse utilizador.</string>
<string name="user_dialog_username_hint">Nome de utilizador</string>
<string name="user_dialog_password_hint_add">Palavra-passe</string>
<string name="user_dialog_password_hint_edit">Palavra-passe (se deixada em branco não será alterada)</string>
<string name="user_dialog_button_cancel">Cancelar</string>
<string name="user_dialog_button_add">Adicionar utilizador</string>
<string name="user_dialog_button_delete">Eliminar utilizador</string>
<string name="user_dialog_button_save">Guardar</string>
<string name="settings_notifications_insistent_max_priority_title">Continuar a alertar para a prioridade máxima</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_enabled">Continuar a alertar</string>
<string name="channel_notifications_group_default_name">Padrão</string>
<string name="detail_item_cannot_open_apk">As aplicações já não podem ser instaladas. Em vez disso, descarregue pelo navegador. Consulte a questão #531 no GitHub para mais detalhes.</string>
<string name="settings_notifications_insistent_max_priority_summary_enabled">As notificações de prioridade máxima alertam continuamente até serem descartadas</string>
<string name="settings_notifications_insistent_max_priority_summary_disabled">As notificações de prioridade máxima alertam apenas uma vez</string>
<string name="detail_settings_notifications_dedicated_channels_title">Configurações de notificação personalizadas</string>
<string name="detail_settings_notifications_dedicated_channels_summary_on">A usar configurações personalizadas para esta subscrição</string>
<string name="detail_settings_notifications_dedicated_channels_summary_off">A usar as configurações padrão (sons, substituição de \"Não incomodar\", etc.)</string>
<string name="detail_settings_notifications_open_channels_title">Definir configurações de notificação</string>
<string name="detail_settings_notifications_open_channels_summary">Sobreposição de \"Não incomodar\" (NI), sons, etc.</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_disabled">Alertar apenas uma vez</string>
</resources>

View file

@ -1,346 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="settings_backup_restore_restore_successful">Restaurat cu succes</string>
<string name="settings_advanced_record_logs_title">Înregistrează jurnale</string>
<string name="settings_advanced_export_logs_summary">Copiază jurnal în clipboard, sau uploadează pe nopaste.net (deținut de autorul ntfy). Numele gazdelor sau topicele pot fi cenzurate, notificările nu vor fi niciodată.</string>
<string name="settings_advanced_export_logs_error_uploading">Nu s-au putut încărca jurnalele: %1$s</string>
<string name="settings_about_version_format">ntfy %1$s (%2$s)</string>
<string name="settings_advanced_connection_protocol_entry_ws">WebSockets</string>
<string name="settings_about_version_copied_to_clipboard_message">Copiat în clipboard</string>
<string name="detail_settings_notifications_instant_summary_on">Notificările sunt primite instantaneu. Necesită un serviciu în prim plan și consumă mai multă baterie.</string>
<string name="detail_settings_notifications_dedicated_channels_title">Setări personalizate pentru notificări</string>
<string name="detail_settings_appearance_icon_set_summary">Setează o pictogramă care să fie afișată în notificări</string>
<string name="channel_subscriber_notification_instant_text_three">Abonat la trei topice cu livrare instantanee</string>
<string name="detail_settings_about_topic_url_title">URL-ul topicului</string>
<string name="channel_subscriber_service_name">Serviciul abonărilor</string>
<string name="user_dialog_password_hint_edit">Parolă (neschimbată dacă este lăsată necompletată)</string>
<string name="channel_subscriber_notification_instant_text_two">Abonat la două topice cu livrare instantanee</string>
<string name="channel_subscriber_notification_instant_text">Abonat pentru primirea topicelor cu livrare instantanee</string>
<string name="channel_subscriber_notification_instant_text_five">Abonat la cinci topice cu livrare instantanee</string>
<string name="channel_subscriber_notification_instant_text_more">Abonat la %1$d topice cu livrare instantanee</string>
<string name="channel_subscriber_notification_noinstant_text_three">Abonat la trei topice</string>
<string name="channel_subscriber_notification_noinstant_text_two">Abonat la două topice</string>
<string name="channel_subscriber_notification_noinstant_text_four">Abonat la patru topice</string>
<string name="main_banner_websocket_text">Trecerea la WebSockets este modalitatea recomandată de a vă conecta la serverul dumneavostră, și poate îmbunătăți durata de viață a bateriei, dar poate necesita <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">configurare suplimentară în proxy-ul dumneavostră</a>. Acest lucru poate fi comutat în setări.</string>
<string name="detail_item_cannot_download">Nu se poate deschide sau descărca atașamentul. Link-ul a expirat și nu s-a găsit niciun fișier local.</string>
<string name="notification_dialog_muted_until_toast_message">Notificări oprite până la %1$s</string>
<string name="notification_popup_file">%1$s
\nFișier: %2$s</string>
<string name="notification_popup_file_download_successful">%1$s
\nFișier: %2$s, descărcat</string>
<string name="notification_popup_file_download_failed">%1$s
\nFile: %2$s, descărcare eșuată</string>
<string name="settings_notifications_muted_until_show_all">Se afișează toate notificările</string>
<string name="settings_notifications_min_priority_summary_any">Se afișează toate notificările</string>
<string name="settings_notifications_priority_low">mică</string>
<string name="settings_notifications_priority_high">mare</string>
<string name="settings_notifications_priority_max">maximă</string>
<string name="settings_notifications_channel_prefs_summary">Suprascriere nu deranjați (DND), sunete, etc.</string>
<string name="settings_notifications_insistent_max_priority_summary_enabled">Notificările cu prioritate maximă se alertă continuu până la respingere</string>
<string name="settings_advanced_broadcast_summary_enabled">Aplicațiile pot primi notificări primite ca difuzări</string>
<string name="settings_advanced_broadcast_summary_disabled">Aplicațiile nu pot primi notificări ca difuzări</string>
<string name="settings_advanced_export_logs_scrub_dialog_text">Aceste topice/nume de gazde au fost înlocuite cu nume de fructe, ca să puteți distribui jurnalul fără griji:
\n
\n%1$s
\n
\nParolele sunt criptate, dar nu sunt listate aici.</string>
<string name="settings_advanced_connection_protocol_summary_ws">Folosește WebSockets pentru conectarea la server. Asta este metoda recomandată, dar ar putea necesita setări adiționale în proxy-ul dumneavoastră</string>
<string name="detail_settings_appearance_icon_remove_title">Pictogramă abonament (apăsați pentru a elimina)</string>
<string name="settings_advanced_connection_protocol_entry_jsonhttp">Flux JSON prin HTTP</string>
<string name="settings_notifications_auto_delete_title">Șterge notificări</string>
<string name="settings_notifications_auto_download_always">Descarcă totul automat</string>
<string name="settings_notifications_auto_download_100k">Dacă e mai mic de 100 kB</string>
<string name="settings_notifications_auto_download_500k">Dacă e mai mic de 500 kB</string>
<string name="settings_notifications_auto_download_1m">Dacă e mai mic de 1 MB</string>
<string name="settings_notifications_auto_download_5m">Dacă e mai mic de 5 MB</string>
<string name="settings_notifications_auto_download_10m">Dacă e mai mic de 10 MB</string>
<string name="settings_notifications_auto_download_50m">Dacă e mai mic de 50 MB</string>
<string name="settings_notifications_auto_delete_never">Niciodată</string>
<string name="settings_notifications_auto_delete_three_days">Peste 3 zile</string>
<string name="settings_notifications_insistent_max_priority_title">Păstrează alertele pentru prioritatea maximă</string>
<string name="settings_notifications_insistent_max_priority_summary_disabled">Notificările cu prioritate maximă se alertă o singură dată</string>
<string name="settings_general_header">General</string>
<string name="settings_general_default_base_url_title">Server implicit</string>
<string name="settings_general_default_base_url_message">Introduceți URL-ul rădăcinii a serverului dvs. pentru utilizarea implicită atunci când vă abonați la topice noi și/sau când partajați în topice.</string>
<string name="settings_general_default_base_url_default_summary">%1$s (implicit)</string>
<string name="settings_general_users_prefs_user_add">Adaugă utilizatori</string>
<string name="settings_general_users_prefs_user_add_summary">Crează un utilizator nou pentru un server nou</string>
<string name="settings_general_users_title">Gestionați utilizatorii</string>
<string name="settings_general_users_summary">Adaugă/șterge utilizatori pentru subiecte protejate</string>
<string name="settings_general_users_prefs_user_not_used">Nu este folosit de niciun topic</string>
<string name="settings_general_users_prefs_user_used_by_one">Folosit de topicul %1$s</string>
<string name="settings_general_users_prefs_user_used_by_many">Folosit de topicele %1$s</string>
<string name="settings_general_dark_mode_summary_system">Folosește implicitul sistemului</string>
<string name="settings_general_dark_mode_summary_light">Modul luminos pornit</string>
<string name="settings_general_dark_mode_summary_dark">Mod întunecat pornit. Ești un vampir\?</string>
<string name="settings_general_dark_mode_entry_system">Folosește implicitul sistemului</string>
<string name="settings_general_dark_mode_entry_light">Mod luminos</string>
<string name="settings_general_dark_mode_entry_dark">Mod întunecat</string>
<string name="settings_backup_restore_backup_entry_everything">Totul</string>
<string name="settings_backup_restore_backup_entry_everything_no_users">Totul, înafară de utilizatori</string>
<string name="settings_backup_restore_header">Backup și restaurare</string>
<string name="settings_backup_restore_backup_title">Back up în fișier</string>
<string name="settings_backup_restore_backup_summary">Exportați configurația, notificările și utilizatorii</string>
<string name="settings_backup_restore_backup_entry_settings_only">Doar setări</string>
<string name="settings_backup_restore_backup_successful">Backup creat</string>
<string name="settings_backup_restore_backup_failed">Backup eșuat: %1$s</string>
<string name="settings_backup_restore_restore_title">Restaurează din fișier</string>
<string name="settings_backup_restore_restore_failed">Restaurare eșuată: %1$s</string>
<string name="settings_advanced_header">Avansat</string>
<string name="settings_advanced_broadcast_title">Difuzați mesaje</string>
<string name="settings_advanced_record_logs_summary_enabled">Se salvează (până la 1,000 de intrări) pe dispozitiv…</string>
<string name="settings_advanced_export_logs_title">Copiază/uploadează jurnale</string>
<string name="settings_advanced_export_logs_entry_copy_original">Copiază în clipboard</string>
<string name="settings_advanced_export_logs_entry_copy_scrubbed">Copiază în clipboard (cenzurat)</string>
<string name="settings_advanced_export_logs_entry_upload_original">Uploadează și copiază linkul</string>
<string name="settings_advanced_export_logs_entry_upload_scrubbed">Uploadează și copiază linkul (cenzurat)</string>
<string name="settings_advanced_export_logs_copied_logs">Jurnale copiate în clipboard</string>
<string name="settings_advanced_export_logs_uploading">Încărcare jurnal …</string>
<string name="settings_advanced_export_logs_copied_url">Jurnal încărcat și URL copiat</string>
<string name="settings_advanced_record_logs_summary_disabled">Activați înregistrarea în jurnal, astfel încât să puteți partaja jurnalele mai târziu pentru a diagnostica probleme.</string>
<string name="settings_advanced_export_logs_scrub_dialog_button_ok">OK</string>
<string name="settings_advanced_export_logs_scrub_dialog_empty">Niciun topic sau nume de gazde au fost redactate. Poate nu ai niciun abonament\?</string>
<string name="settings_advanced_clear_logs_summary">Șterge jurnalele înregistrate anterior, și începe de la capăt</string>
<string name="settings_advanced_clear_logs_deleted_toast">Jurnale șterse</string>
<string name="settings_advanced_connection_protocol_title">Protocolul conexiunii</string>
<string name="settings_advanced_clear_logs_title">Șterge jurnale</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Utilizați un flux JSON prin HTTP pentru conectarea la server. Această metodă este efectivă, dar poate folosi mai multă baterie.</string>
<string name="settings_about_header">Despre</string>
<string name="settings_about_version_title">Versiune</string>
<string name="detail_settings_notifications_instant_title">Primire instantanee</string>
<string name="detail_settings_notifications_instant_summary_off">Notificările sunt primite cu Firebase. Primirea poate fi întârziată, dar folosește mai puțină baterie.</string>
<string name="detail_settings_notifications_open_channels_title">Configurează setările pentru notificări</string>
<string name="detail_settings_notifications_dedicated_channels_summary_on">Se folosesc setări personalizate pentru acest abonament</string>
<string name="detail_settings_notifications_dedicated_channels_summary_off">Folosește setările implicite (sunete, trece peste Nu deranjați, etc.)</string>
<string name="detail_settings_appearance_header">Aparență</string>
<string name="detail_settings_notifications_open_channels_summary">Suprascrierea \"nu deranjați\" (DND), sunete, etc.</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_enabled">Alertează în continuare</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_disabled">Alertează doar o dată</string>
<string name="detail_settings_appearance_icon_remove_summary">Pictograma afișată în notificări pentru acest topic</string>
<string name="detail_settings_appearance_display_name_title">Nume de afișare</string>
<string name="detail_settings_appearance_icon_set_title">Pictogramă abonament</string>
<string name="detail_settings_appearance_icon_error_saving">Nu s-a putut salva pictograma: %1$s</string>
<string name="detail_settings_appearance_display_name_message">Setează un nume de afișare personalizat pentru acest abonament. Lăsați necompletat pentru numele implicit (%1$s).</string>
<string name="detail_settings_appearance_display_name_default_summary">%1$s (implicit)</string>
<string name="detail_settings_global_setting_title">Folosește setarea globală</string>
<string name="detail_settings_about_header">Despre</string>
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">Copiat în clipboard</string>
<string name="detail_settings_global_setting_suffix">folosind setarea globală</string>
<string name="user_dialog_title_add">Adaugă utilizator</string>
<string name="user_dialog_title_edit">Modifică utilizator</string>
<string name="user_dialog_description_add">Poți adaugă un utilizator aici. Toate topicele pentru serverul specificat vor folosi acest utilizator.</string>
<string name="user_dialog_description_edit">Puteți edita numele de utilizator/parola pentru utilizatorul selectat, sau îl puteți șterge.</string>
<string name="user_dialog_base_url_hint">URL-ul serviciului</string>
<string name="user_dialog_username_hint">Nume de utilizator</string>
<string name="user_dialog_password_hint_add">Parolă</string>
<string name="user_dialog_button_add">Adaugă utilizator</string>
<string name="user_dialog_button_cancel">Anulează</string>
<string name="user_dialog_button_delete">Șterge utilizator</string>
<string name="user_dialog_button_save">Salvează</string>
<string name="channel_notifications_default_name">Prioritate normală</string>
<string name="channel_subscriber_notification_title">Ascultând pentru notificări primite</string>
<string name="channel_notifications_max_name">Prioritate maximă</string>
<string name="channel_notifications_group_default_name">Implicit</string>
<string name="channel_subscriber_notification_instant_text_one">Abonat la un subiect cu livrare instantanee</string>
<string name="channel_subscriber_notification_instant_text_four">Abonat la patru topice cu livrare instantanee</string>
<string name="channel_subscriber_notification_instant_text_six">Abonat la șase topice cu livrare instantanee</string>
<string name="channel_subscriber_notification_noinstant_text">Abonat la topice</string>
<string name="channel_subscriber_notification_noinstant_text_one">Abonat la un topic</string>
<string name="channel_subscriber_notification_noinstant_text_five">Abonat la cinci topice</string>
<string name="channel_subscriber_notification_noinstant_text_six">Abonat la șase topice</string>
<string name="channel_subscriber_notification_noinstant_text_more">Abonat la %1$d topice</string>
<string name="refresh_message_result">%1$d notificări primite</string>
<string name="refresh_message_no_results">Totul este la zi</string>
<string name="refresh_message_error">Nu s-au putut actualiza %1$d abonări
\n
\n%2$s</string>
<string name="refresh_message_error_one">Nu s-a putut actualiza abonarea: %1$s</string>
<string name="main_action_bar_title">Topice abonate</string>
<string name="main_menu_rate_title">Evaluează aplicația</string>
<string name="main_menu_notifications_disabled_forever">Notificări dezactivate</string>
<string name="main_menu_notifications_disabled_until">Notificări dezactivate până la %1$s</string>
<string name="main_menu_report_bug_title">Raportează o problemă</string>
<string name="main_menu_docs_title">Citește documentația</string>
<string name="main_action_mode_delete_dialog_message">Dezabonează-te de la topicele selectate și șterge notificările permanent\?</string>
<string name="main_menu_donate_title">Donează 💸</string>
<string name="main_item_status_unified_push">%1$s (UnifiedPush)</string>
<string name="main_add_button_description">Adaugă abonament</string>
<string name="main_item_status_text_not_one">%1$d notificări</string>
<string name="main_item_status_reconnecting">reconectare …</string>
<string name="main_item_date_yesterday">ieri</string>
<string name="main_no_subscriptions_text">Se pare că nu încă ești abonat la nimic.</string>
<string name="main_banner_battery_text">Optimizarea bateriei ar trebui să fie oprită pentru a preveni probleme de livrare a notificărilor.</string>
<string name="main_banner_battery_button_remind_later">Întreabă mai târziu</string>
<string name="main_how_to_intro">Apasă pe + pentru a crea sau pentru a te abona la un topic. Apoi primiți notificări pe dispozitivul dvs. atunci când trimiteți mesaje prin intermediul PUT sau POST.</string>
<string name="main_how_to_link">Instrucțiuni detaliate disponibile pe ntfy.sh, și pe documentație.</string>
<string name="main_unified_push_toast">Această abonare este gestionat de %1$s prin UnifiedPush</string>
<string name="main_banner_battery_button_dismiss">Ignoră</string>
<string name="detail_deep_link_subscribed_toast_message">Abonat la topicul %1$s</string>
<string name="detail_item_snack_deleted">Notificare ștearsă</string>
<string name="detail_item_tags">Etichete: %1$s</string>
<string name="detail_item_snack_undo">Anulează</string>
<string name="detail_item_menu_delete">Șterge fișierul</string>
<string name="detail_item_menu_cancel">Oprește descărcarea</string>
<string name="detail_item_menu_save_file">Salvează fișierul</string>
<string name="detail_item_saved_successfully">Salvat ca \"%1$s\" în directorul \"Downloads\"</string>
<string name="detail_item_menu_copy_contents">Copiază notificarea</string>
<string name="detail_item_menu_copy_contents_copied">Notificare copiată în clipboard</string>
<string name="detail_item_cannot_open">Nu se poate deschide atașametul: %1$s</string>
<string name="detail_item_cannot_open_url">Nu se poate deschide URL-ul: %1$s</string>
<string name="detail_item_cannot_open_apk">Aplicațiile nu mai pot fi instalate. Descarcă prin intermediul browser-ului. Consultați problema #531 pentru detalii.</string>
<string name="detail_item_download_info_deleted_expired">șters, link expirat</string>
<string name="detail_item_download_info_deleted_expires_x">șters, link expiră la %1$s</string>
<string name="detail_item_download_info_download_failed_expires_x">descărcare eșuată, linkul expiră la %1$s</string>
<string name="detail_menu_notifications_enabled">Notificări pornite</string>
<string name="detail_menu_enable_instant">Pornire primire instantanee</string>
<string name="detail_menu_notifications_disabled_forever">Notificări oprite</string>
<string name="detail_menu_notifications_disabled_until">Notificări oprite până la %1$s</string>
<string name="detail_menu_copy_url">Copiază adresa topicului</string>
<string name="detail_menu_clear">Șterge toate notificările</string>
<string name="detail_menu_unsubscribe">Dezabonează-te</string>
<string name="detail_action_mode_menu_copy">Copiază</string>
<string name="detail_menu_settings">Setări abonament</string>
<string name="detail_action_mode_menu_delete">Șterge</string>
<string name="detail_action_mode_delete_dialog_message">Șterge notificarea/notificările selectate permanent\?</string>
<string name="detail_settings_title">Setări abonament</string>
<string name="share_menu_send">Distribuie</string>
<string name="share_content_text_hint">Adaugă conținut pentru a distribui aici</string>
<string name="share_content_image_text">O imagine a fost distribuită cu tine</string>
<string name="share_content_file_error">Nu se poate citi informația fișierului: %1$s</string>
<string name="share_topic_title">Distribuie la</string>
<string name="notification_dialog_title">Oprește notificările</string>
<string name="share_successful">Mesaj publicat</string>
<string name="notification_dialog_save">Salvează</string>
<string name="notification_dialog_enabled_toast_message">Notificări reactivate</string>
<string name="notification_dialog_show_all">Arată toate notificările</string>
<string name="notification_dialog_muted_forever_toast_message">Notificări oprite</string>
<string name="notification_dialog_1h">O oră</string>
<string name="notification_dialog_forever">Până la reluare</string>
<string name="notification_dialog_2h">2 ore</string>
<string name="notification_dialog_8h">8 ore</string>
<string name="notification_dialog_tomorrow">Până mâine</string>
<string name="notification_popup_action_open">Deschide</string>
<string name="notification_popup_action_browse">Răsfoiește</string>
<string name="notification_popup_action_download">Descarcă</string>
<string name="notification_popup_file_downloading">Se descarcă %1$s, %2$d%%
\n%3$s</string>
<string name="notification_popup_action_cancel">Anulează</string>
<string name="notification_popup_user_action_failed">%1$s eșuat: %2$s</string>
<string name="settings_notifications_muted_until_title">Oprire notificări</string>
<string name="settings_notifications_muted_until_forever">Notificări oprite până la reluare</string>
<string name="settings_notifications_muted_until_x">Notificări oprite până la %1$s</string>
<string name="settings_notifications_header">Notificări</string>
<string name="settings_notifications_min_priority_summary_x_or_higher">Arată notificările dacă prioritatea este %1$d (%2$s) sau mai înaltă</string>
<string name="settings_notifications_min_priority_summary_max">Arată notificările dacă prioritatea este 5 (maximă)</string>
<string name="settings_notifications_min_priority_min">Orice prioritate</string>
<string name="settings_notifications_min_priority_default">Prioritate implicită sau mai înaltă</string>
<string name="settings_notifications_min_priority_low">Prioritate mică sau mai mare</string>
<string name="settings_notifications_priority_min">minim</string>
<string name="settings_notifications_auto_download_title">Descarcă atașamentele</string>
<string name="settings_notifications_priority_default">implicită</string>
<string name="settings_notifications_auto_download_summary_smaller_than_x">Descărcare automată a atașamentelor până la %1$s</string>
<string name="settings_notifications_auto_download_never">Niciodată să nu se descarce automat ceva</string>
<string name="channel_notifications_min_name">Prioritate minimă</string>
<string name="channel_notifications_low_name">Prioritate mică</string>
<string name="channel_notifications_high_name">Prioritate mare</string>
<string name="main_menu_notifications_enabled">Notificări pornite</string>
<string name="main_menu_settings_title">Setări</string>
<string name="main_action_mode_menu_unsubscribe">Dezabonează-te</string>
<string name="main_action_mode_delete_dialog_permanently_delete">Șterge permanent</string>
<string name="main_item_status_text_one">%1$d notificare</string>
<string name="main_action_mode_delete_dialog_cancel">Anulare</string>
<string name="main_banner_battery_button_fix_now">Rezolvă acum</string>
<string name="main_banner_websocket_button_remind_later">Întreabă mai târziu</string>
<string name="main_banner_websocket_button_enable_now">Activează acum</string>
<string name="add_dialog_title">Abonează-te la topic</string>
<string name="detail_how_to_link">Instrucțiuni detaliate disponibile pe ntfy.sh, și în documentație.</string>
<string name="detail_clear_dialog_message">Șterge toate notificările în acest topic\?</string>
<string name="detail_delete_dialog_message">Dezabonează-te de la acest topic și șterge toate notificările primite\?</string>
<string name="detail_clear_dialog_permanently_delete">Șterge permanent</string>
<string name="detail_clear_dialog_cancel">Anulează</string>
<string name="detail_item_menu_open">Deschide fișier</string>
<string name="detail_item_menu_copy_url_copied">URL copiat în clipboard</string>
<string name="detail_item_download_info_deleted">șters</string>
<string name="detail_item_download_info_download_failed">descărcare eșuată</string>
<string name="detail_item_download_info_download_failed_expired">descărcare eșuată, linkul a expirat</string>
<string name="detail_item_menu_download">Descarcă fișierul</string>
<string name="detail_item_menu_copy_url">Copiază URL</string>
<string name="detail_item_cannot_open_not_found">Nu se poate deschide atașamentul: Fișierul s-ar putea să fi fost șters, sau nu există o aplicație instalată pentru a îl deschide.</string>
<string name="detail_item_download_info_not_downloaded">nu s-a descărcat</string>
<string name="detail_item_download_info_not_downloaded_expires_x">nu s-a descărcat, expiră la %1$s</string>
<string name="detail_item_cannot_delete">Nu se poate șterge atașamentul: %1$s</string>
<string name="detail_item_download_info_not_downloaded_expired">nu s-a descărcat, link expirat</string>
<string name="detail_item_download_failed">Nu se poate descărca atașamentul: %1$s</string>
<string name="detail_menu_disable_instant">Oprește primirea instantanee</string>
<string name="share_content_image_error">Nu se poate citi imaginea: %1$s</string>
<string name="detail_action_mode_delete_dialog_permanently_delete">Ștergere permanentă</string>
<string name="share_title">Distribuie</string>
<string name="detail_action_mode_delete_dialog_cancel">Anulează</string>
<string name="share_content_title">Previzualizare mesaj</string>
<string name="share_content_file_text">Un fișier a fost distribuit cu tine</string>
<string name="share_suggested_topics">Topice sugerate</string>
<string name="settings_notifications_auto_download_summary_never">Niciodată nu descarcă atașamente automat</string>
<string name="notification_dialog_cancel">Anulează</string>
<string name="notification_dialog_30min">30 de minute</string>
<string name="settings_title">Setări</string>
<string name="settings_notifications_min_priority_title">Prioritate minimă</string>
<string name="settings_notifications_min_priority_high">Prioritate mare sau mai înaltă</string>
<string name="settings_notifications_min_priority_max">Doar prioritate maximă</string>
<string name="settings_notifications_auto_delete_one_week">Peste o saptămână</string>
<string name="settings_notifications_auto_delete_summary_three_days">Șterge notificările automat în 3 zile</string>
<string name="settings_notifications_channel_prefs_title">Setări canal</string>
<string name="settings_notifications_auto_download_summary_always">Descarcă toate atașamentele automat</string>
<string name="settings_notifications_auto_delete_summary_never">Nu șterge niciodată notificarile automat</string>
<string name="settings_notifications_auto_delete_summary_one_month">Șterge notificările automat în o lună</string>
<string name="settings_notifications_auto_delete_summary_three_months">Șterge notificările automat în 3 luni</string>
<string name="settings_general_dark_mode_title">Mod întunecat</string>
<string name="settings_notifications_auto_delete_summary_one_day">Șterge notificările automat în o zi</string>
<string name="settings_general_users_prefs_title">Utilizatori</string>
<string name="settings_general_users_prefs_user_add_title">Adaugă un utilizator nou</string>
<string name="settings_notifications_auto_delete_summary_one_week">Șterge notificările automat în o săptămână</string>
<string name="settings_notifications_auto_delete_one_day">Peste o zi</string>
<string name="settings_notifications_auto_delete_one_month">Peste o lună</string>
<string name="settings_notifications_auto_delete_three_months">Peste 3 luni</string>
<string name="add_dialog_use_another_server">Folosește alt server</string>
<string name="add_dialog_button_cancel">Anulează</string>
<string name="add_dialog_button_back">Înapoi</string>
<string name="add_dialog_button_login">Loghează-te</string>
<string name="add_dialog_error_connection_failed">Conexiunea a eșuat: %1$s</string>
<string name="add_dialog_login_title">Logare necesară</string>
<string name="add_dialog_login_description">Acest topic necesită să te loghezi. Vă rugăm să introduceți un nume de utilizator și o parola.</string>
<string name="add_dialog_login_username_hint">Nume de utilizator</string>
<string name="add_dialog_login_password_hint">Parolă</string>
<string name="add_dialog_login_error_not_authorized">Logare eșuată. Utilizatorul %1$s nu este autorizat.</string>
<string name="add_dialog_login_new_user">Utilizator nou</string>
<string name="detail_no_notifications_text">Nu ai primit încă notificări pentru acest topic.</string>
<string name="detail_how_to_example">Exemplu (folosing curl):<br/><tt>$ curl -d \"Salut\" %1$s</tt></string>
<string name="detail_delete_dialog_cancel">Anulează</string>
<string name="detail_test_title">Test: Poți specifica un titlu dacă dorești.</string>
<string name="detail_test_message">Această este o notificare de test de la aplicația ntfy pentru Android. Are nivelul priorității %1$d. Dacă trimiți altă notificare, s-ar putea să arate altfel.</string>
<string name="detail_test_message_error">Nu se poate trimite mesajul: %1$s</string>
<string name="detail_test_message_error_unauthorized_anon">Nu se poate trimite mesajul: Publicarea anonimă nu este permisă.</string>
<string name="detail_test_message_error_unauthorized_user">Nu se poate trimite mesajul: Utilizatorul \"%1$s\" nu este autorizat.</string>
<string name="detail_test_message_error_too_large">Nu se poate trimite mesajul: Atașamentul este prea mare.</string>
<string name="detail_copied_to_clipboard_message">Copiat în clipboard</string>
<string name="detail_instant_delivery_enabled">Primire instantanee pornită</string>
<string name="detail_instant_delivery_disabled">Primire instantanee oprită</string>
<string name="main_banner_websocket_button_dismiss">Ignoră</string>
<string name="add_dialog_description_below">Topicele nu pot fi protejate cu parolă, așadar alegeți un nume greu de ghicit. Odată abonat, puteți PUT/POST notificări</string>
<string name="add_dialog_topic_name_hint">Numele topicului, exemplu: alertele_lui_phil</string>
<string name="add_dialog_use_another_server_description">Introduceți URL-urile serviciilor mai jos pentru a vă abona la topice de la alte servere.</string>
<string name="add_dialog_instant_delivery">Primire instantanee în modul doze</string>
<string name="add_dialog_foreground_description">Primirea instantanee este întotdeauna pornită pentru gazdele înafară de %1$s.</string>
<string name="add_dialog_button_subscribe">Abonare</string>
<string name="add_dialog_base_urls_dropdown_choose">Alege URL-ul serviciului</string>
<string name="add_dialog_base_urls_dropdown_clear">Șterge URL-ul serviciului</string>
<string name="detail_how_to_intro">Pentru a trimite notificări pentru acest topic, pur și simplu trimiteți o cerere PUT sau POST la URL-ul topicului.</string>
<string name="detail_delete_dialog_permanently_delete">Ștergere permanentă</string>
<string name="add_dialog_instant_delivery_description">Asigură ca mesajele să fie primite imediat, chiar dacă dispozitivul este inactiv.</string>
<string name="detail_item_cannot_save">Nu se poate salva atașamentul: %1$s</string>
<string name="detail_item_download_info_downloading_x_percent">%1$d%% descărcat</string>
<string name="detail_menu_test">Trimite notificare de probă</string>
<string name="settings_backup_restore_restore_summary">Importă setări, notificări și utilizatori</string>
<string name="settings_advanced_unifiedpush_summary_enabled">ntfy va avea rol de distribuitor UnifiedPush</string>
<string name="settings_advanced_unifiedpush_title">Activează UnifiedPush</string>
<string name="settings_advanced_unifiedpush_summary_disabled">ntfy nu va avea rol de distribuitor UnifiedPush</string>
</resources>

View file

@ -1,20 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="main_action_mode_delete_dialog_cancel">Отмена</string>
<string name="channel_notifications_default_name">Стандартный приоритет</string>
<string name="channel_notifications_high_name">Высокий приоритет</string>
<string name="channel_notifications_max_name">Максимальный приоритет</string>
<string name="channel_notifications_default_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_notifications_min_name">Минимальный приоритет</string>
<string name="channel_notifications_low_name">Низкий приоритет</string>
<string name="main_menu_notifications_disabled_forever">Уведомления заглушены</string>
<string name="channel_notifications_min_name">Уведомления (мин. приоритет)</string>
<string name="channel_notifications_low_name">Уведомления (низкий приоритет)</string>
<string name="main_menu_notifications_disabled_forever">Уведомления приостановлены</string>
<string name="main_menu_notifications_enabled">Уведомления включены</string>
<string name="main_menu_report_bug_title">Сообщить об ошибке</string>
<string name="main_menu_settings_title">Настройки</string>
<string name="main_menu_docs_title">Документация</string>
<string name="main_action_mode_delete_dialog_permanently_delete">Удалить навсегда</string>
<string name="detail_clear_dialog_cancel">Отмена</string>
<string name="detail_delete_dialog_message">Отписаться от этой темы и удалить все полученные уведомления\?</string>
<string name="detail_delete_dialog_message">Отписаться от этой темы, и удалить все полученые уведомления\?</string>
<string name="detail_delete_dialog_permanently_delete">Удалить навсегда</string>
<string name="detail_delete_dialog_cancel">Отмена</string>
<string name="detail_test_title">Тест: Вы можете установить заголовок, если хотите.</string>
@ -28,7 +28,7 @@
<string name="detail_item_menu_copy_contents">Скопировать уведомление</string>
<string name="detail_item_menu_copy_contents_copied">Уведомление скопировано</string>
<string name="detail_item_saved_successfully">Сохранён как \"%1$s\" в папке \"Downloads\"</string>
<string name="detail_menu_notifications_disabled_until">Уведомления заглушены до %1$s</string>
<string name="detail_menu_notifications_disabled_until">Уведомления приостановлены до %1$s</string>
<string name="detail_menu_enable_instant">Включить моментальную доставку</string>
<string name="detail_menu_disable_instant">Выключить моментальную доставку</string>
<string name="detail_menu_test">Отправить тестовое уведомление</string>
@ -44,14 +44,14 @@
<string name="detail_settings_title">Настройки подписок</string>
<string name="share_title">Поделиться</string>
<string name="share_menu_send">Поделиться</string>
<string name="notification_dialog_title">Заглушить уведомления</string>
<string name="notification_dialog_title">Приостановить уведомления</string>
<string name="settings_notifications_auto_download_100k">Если меньше 100 кб</string>
<string name="settings_notifications_auto_delete_never">Никогда</string>
<string name="settings_notifications_auto_delete_three_days">Черед три дня</string>
<string name="settings_notifications_auto_delete_one_day">Через один день</string>
<string name="settings_notifications_auto_delete_one_week">Через неделю</string>
<string name="settings_notifications_auto_delete_one_month">Через месяц</string>
<string name="settings_notifications_auto_delete_three_months">Через три месяца</string>
<string name="settings_notifications_auto_delete_three_months">Чкрез три месяца</string>
<string name="settings_general_header">Общие</string>
<string name="settings_general_default_base_url_title">Сервер по умолчанию</string>
<string name="settings_general_default_base_url_default_summary">%1$s (по умолчанию)</string>
@ -70,14 +70,15 @@
<string name="main_banner_battery_button_remind_later">Спросить позже</string>
<string name="main_banner_battery_button_fix_now">Исправить</string>
<string name="main_banner_battery_button_dismiss">Закрыть</string>
<string name="main_banner_websocket_button_dismiss">Закрыть</string>
<string name="main_banner_json_stream_button_dismiss">Закрыть</string>
<string name="main_add_button_description">Добавить подписку</string>
<string name="main_action_mode_menu_unsubscribe">Отписаться</string>
<string name="main_item_status_text_one">%1$d уведомление</string>
<string name="main_item_status_reconnecting">повторное подключение …</string>
<string name="main_no_subscriptions_text">Похоже, у вас ещё нет подписок.</string>
<string name="main_action_mode_delete_dialog_message">Отписаться от выбранных тем, и навсегда удалить все уведомления\?</string>
<string name="main_banner_websocket_button_remind_later">Спросить позже</string>
<string name="main_banner_json_stream_button_remind_later">Спросить позже</string>
<string name="main_banner_json_stream_button_learn_more">Узнать больше</string>
<string name="add_dialog_title">Подписаться на тему</string>
<string name="add_dialog_button_cancel">Отмена</string>
<string name="main_unified_push_toast">Эта подписка управляется %1$s через UnifiedPush</string>
@ -88,7 +89,7 @@
<string name="detail_item_menu_delete">Удалить файл</string>
<string name="detail_item_menu_download">Скачать файл</string>
<string name="detail_item_menu_cancel">Отменить скачивание</string>
<string name="detail_item_cannot_open_url">URL-адрес не открывается: %1$s</string>
<string name="detail_item_cannot_open_click_url">URL-адрес не открывается: %1$s</string>
<string name="notification_popup_action_browse">Выбрать</string>
<string name="notification_popup_action_cancel">Отмена</string>
<string name="settings_notifications_header">Уведомления</string>
@ -110,237 +111,27 @@
<string name="detail_item_cannot_open">Вложение не открывается: %1$s</string>
<string name="detail_item_cannot_open_not_found">Вложение не открывается: Возможно файл был удалёл, либо нет установленного приложения, способного открыть файл.</string>
<string name="detail_menu_notifications_enabled">Уведомления включены</string>
<string name="detail_menu_notifications_disabled_forever">Уведомления заглушены</string>
<string name="detail_menu_notifications_disabled_forever">Уведомления приостановлены</string>
<string name="notification_dialog_save">Сохранить</string>
<string name="notification_dialog_muted_until_toast_message">Уведомления заглушены до %1$s</string>
<string name="notification_dialog_muted_until_toast_message">Уведомления приостановлены до %1$s</string>
<string name="notification_popup_action_open">Открыть</string>
<string name="notification_popup_action_download">Скачать</string>
<string name="notification_popup_file">%1$s
\nФайл: %2$s</string>
<string name="notification_dialog_cancel">Отмена</string>
<string name="notification_dialog_enabled_toast_message">Уведомления разрешены</string>
<string name="notification_dialog_muted_forever_toast_message">Уведомления заглушены</string>
<string name="notification_dialog_enabled_toast_message">Уведомления возобновлены</string>
<string name="notification_dialog_muted_forever_toast_message">Уведомления приостановлены</string>
<string name="notification_dialog_show_all">Показать все уведомления</string>
<string name="notification_dialog_30min">30 минут</string>
<string name="notification_dialog_8h">8 часов</string>
<string name="notification_dialog_tomorrow">До завтра</string>
<string name="notification_dialog_1h">1 час</string>
<string name="notification_dialog_2h">2 часа</string>
<string name="notification_dialog_forever">До разрешения</string>
<string name="notification_dialog_forever">До возобновления</string>
<string name="settings_title">Настройки</string>
<string name="settings_notifications_min_priority_min">Любой приоритет</string>
<string name="settings_general_users_prefs_user_add">Добавить пользователей</string>
<string name="settings_general_users_prefs_user_add_summary">Создать нового пользователя для нового сервера</string>
<string name="settings_backup_restore_restore_title">Восстановить из файла</string>
<string name="settings_general_users_prefs_user_add_title">Добавить нового пользователя</string>
<string name="main_menu_notifications_disabled_until">Уведомления заглушены до %1$s</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_how_to_intro">Нажмите + чтобы создать или подписаться на тему. Вы будете получать уведомления на вашем устройстве при отправке сообщений через PUT или POST-запросы.</string>
<string name="channel_subscriber_notification_instant_text">Подписан на темы с мгновенной доставкой</string>
<string name="channel_subscriber_notification_instant_text_two">Подписан на две темы с мгновенной доставкой</string>
<string name="channel_subscriber_notification_instant_text_one">Подписан на одну тему с мгновенной доставкой</string>
<string name="channel_subscriber_notification_instant_text_more">Подписан на %1$d тем с мгновенной доставкой</string>
<string name="refresh_message_result">%1$d уведомлений получено</string>
<string name="channel_subscriber_notification_title">Ожидаются входящие уведомления</string>
<string name="channel_subscriber_notification_instant_text_three">Подписан на три темы с мгновенной доставкой</string>
<string name="channel_subscriber_notification_instant_text_four">Подписан на четыре темы с мгновенной доставкой</string>
<string name="main_how_to_link">Подробные инструкции можно найти на ntfy.sh или в документации.</string>
<string name="refresh_message_no_results">Всё обновлено</string>
<string name="add_dialog_instant_delivery">Мгновенная доставка в спящем режиме</string>
<string name="main_banner_battery_text">Оптимизация батареи должна быть выключена, чтобы избежать проблем с доставкой уведомлений.</string>
<string name="add_dialog_error_connection_failed">Ошибка связи: %1$s</string>
<string name="add_dialog_login_title">Требуется вход в аккаунт</string>
<string name="add_dialog_login_description">Эта тема требует авторизации. Пожалуйста, введите имя пользователя и пароль.</string>
<string name="add_dialog_description_below">Темы не могут быть защищены паролем. Используйте название которое сложно угадать. После подписки вы сможете отправлять уведомления через PUT/POST.</string>
<string name="detail_test_message">Это тестовое уведомление от Android-приложения ntfy. Оно имеет уровень приоритета %1$d. Если вы отправите ещё одно, оно может выглядеть по-другому.</string>
<string name="add_dialog_login_error_not_authorized">Вход не удался. Пользователь %1$s не авторизован.</string>
<string name="detail_how_to_intro">Чтобы отправить уведомления на данную тему, просто отправьте PUT or POST на URL-адрес темы.</string>
<string name="detail_how_to_link">Подробные инструкции на сайте ntfy.sh и в документации.</string>
<string name="add_dialog_instant_delivery_description">Гарантирует мгновенную доставку сообщений, даже если устройство неактивно.</string>
<string name="add_dialog_foreground_description">Мгновенная доставка включена для хостов кроме %1$s.</string>
<string name="add_dialog_use_another_server_description">Введите URL-адрес сервиса чтобы подписаться на темы с других серверов.</string>
<string name="detail_item_download_info_not_downloaded_expires_x">не скачано, истекает срок действия %1$s</string>
<string name="detail_item_download_info_download_failed_expired">не удалось скачать, срок действия ссылки истёк</string>
<string name="settings_notifications_min_priority_max">Только максимальный приоритет</string>
<string name="settings_notifications_priority_low">низкий</string>
<string name="settings_notifications_channel_prefs_title">Настройки канала</string>
<string name="settings_notifications_channel_prefs_summary">Управление режимом \"не беспокоить\", звуками и прочим.</string>
<string name="settings_notifications_auto_delete_summary_three_days">Автоматически удалять уведомления через 3 дня</string>
<string name="settings_notifications_auto_delete_summary_one_month">Автоматически удалять уведомления через месяц</string>
<string name="detail_item_cannot_save">Невозможно сохранить вложение: %1$s</string>
<string name="detail_item_cannot_delete">Невозможно удалить вложение: %1$s</string>
<string name="detail_item_download_failed">Невозможно скачать вложение: %1$s</string>
<string name="detail_item_download_info_not_downloaded">не скачано</string>
<string name="detail_item_download_info_not_downloaded_expired">не скачано, срок действия ссылки истёк</string>
<string name="detail_item_download_info_downloading_x_percent">%1$d%% скачан</string>
<string name="detail_item_download_info_deleted">удалено</string>
<string name="detail_item_download_info_deleted_expired">удалено, срок действия ссылки истёк</string>
<string name="detail_item_download_info_deleted_expires_x">удалено, срок действия ссылки истекает %1$s</string>
<string name="detail_item_download_info_download_failed">не удалось скачать</string>
<string name="detail_item_download_info_download_failed_expires_x">не удалось скачать, срок действия ссылки истекает %1$s</string>
<string name="share_content_title">Предварительный просмотр сообщения</string>
<string name="share_content_text_hint">Добавьте контент</string>
<string name="share_content_image_text">С вами поделились картинкой</string>
<string name="share_content_image_error">Невозможно загрузить картинку: %1$s</string>
<string name="share_content_file_text">С вами поделились файлом</string>
<string name="share_content_file_error">Невозможно получить информацию о файле: %1$s</string>
<string name="share_topic_title">Поделиться</string>
<string name="share_suggested_topics">Рекомендуемые темы</string>
<string name="share_successful">Сообщение опубликовано</string>
<string name="notification_popup_file_downloading">Скачивается %1$s, %2$d%%
\n%3$s</string>
<string name="notification_popup_file_download_successful">%1$s
\nФайл: %2$s, скачан</string>
<string name="notification_popup_file_download_failed">%1$s
\nФайл: %2$s, не удалось скачать</string>
<string name="settings_notifications_muted_until_title">Заглушить уведомления</string>
<string name="settings_notifications_muted_until_show_all">Показываются все уведомления</string>
<string name="settings_notifications_muted_until_forever">Уведомления заглушены пока не будут разрешены</string>
<string name="settings_notifications_muted_until_x">Уведомления заглушены до %1$s</string>
<string name="settings_notifications_min_priority_title">Самый низкий приоритет</string>
<string name="settings_notifications_min_priority_summary_any">Отображаются все уведомления</string>
<string name="settings_notifications_min_priority_summary_x_or_higher">Показывать уведомления если приоритет %1$d(%2$s) или выше</string>
<string name="settings_notifications_min_priority_summary_max">Показывать уведомления если приоритет равен 5 (максимальный)</string>
<string name="settings_notifications_min_priority_low">Низкий приоритет или выше</string>
<string name="settings_notifications_min_priority_default">Приоритет по умолчанию и выше</string>
<string name="settings_notifications_min_priority_high">Высокий приоритет и выше</string>
<string name="settings_notifications_priority_min">минимальный</string>
<string name="settings_notifications_priority_default">по умолчанию</string>
<string name="settings_notifications_priority_high">высокий</string>
<string name="settings_notifications_priority_max">максимальный</string>
<string name="settings_notifications_auto_download_title">Скачать вложения</string>
<string name="settings_notifications_auto_download_summary_always">Автоматически скачивать все вложения</string>
<string name="settings_notifications_auto_download_summary_never">Никогда автоматически не скачивать вложения</string>
<string name="settings_notifications_auto_download_summary_smaller_than_x">Автоматически скачивать вложения до %1$s</string>
<string name="settings_notifications_auto_download_never">Никогда ничего не скачивать автоматически</string>
<string name="settings_notifications_auto_download_always">Всегда всё скачивать автоматически</string>
<string name="settings_notifications_auto_download_500k">Если меньше 500 Кб</string>
<string name="settings_notifications_auto_download_1m">Если меньше 1 Мб</string>
<string name="settings_notifications_auto_download_5m">Если меньше 5 Мб</string>
<string name="settings_notifications_auto_download_10m">Если меньше 10 Мб</string>
<string name="settings_notifications_auto_download_50m">Если меньше 50 Мб</string>
<string name="settings_notifications_auto_delete_title">Удалять уведомления</string>
<string name="settings_notifications_auto_delete_summary_never">Никогда автоматически не удалять уведомления</string>
<string name="settings_notifications_auto_delete_summary_one_day">Автоматически удалять уведомления через один день</string>
<string name="settings_notifications_auto_delete_summary_one_week">Автоматически удалять уведомления через неделю</string>
<string name="settings_notifications_auto_delete_summary_three_months">Автоматически удалять уведомления через 3 месяца</string>
<string name="settings_advanced_broadcast_summary_enabled">Приложения могут получать входящие уведомления как вещания</string>
<string name="settings_advanced_record_logs_summary_enabled">Журналирование (макс. 1000 записей) на устройство …</string>
<string name="settings_advanced_export_logs_summary">Скопировать журналы в буфер обмена, или загрузить на nopaste.net (под управлением разработчика ntfy). Доменные имена и темы можно скрыть, уведомления - нет.</string>
<string name="settings_advanced_export_logs_entry_copy_original">Скопировать в буфер обмена</string>
<string name="user_dialog_username_hint">Имя пользователя</string>
<string name="user_dialog_button_save">Сохранить</string>
<string name="settings_general_default_base_url_message">Введите базовый URL вашего сервера, чтобы использовать ваш сервер по умолчанию при подписке на новые темы и/или публикацию в темы.</string>
<string name="settings_general_users_title">Управление пользователями</string>
<string name="settings_general_users_summary">Добавить/удалить пользователей из защищённых тем</string>
<string name="settings_general_users_prefs_title">Пользователи</string>
<string name="settings_general_users_prefs_user_not_used">Не использован в каких-либо темах</string>
<string name="settings_general_users_prefs_user_used_by_one">Использован темой %1$s</string>
<string name="settings_advanced_export_logs_copied_logs">Журналы скопированы в буфер обмена</string>
<string name="settings_advanced_export_logs_uploading">Загрузка журнала …</string>
<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_text">Следующие темы/доменные имена были заменены названиями фруктов, так что вы можете поделиться журналом без беспокойства:
\n
\n%1$s
\n
\nПароли скрыты, но не перечислены здесь.</string>
<string name="settings_advanced_export_logs_scrub_dialog_empty">Никакие темы/доменные имена не были заменены. Может быть у вас нет никаких подписок\?</string>
<string name="settings_advanced_export_logs_scrub_dialog_button_ok">ОК</string>
<string name="settings_advanced_clear_logs_title">Очистить журналы</string>
<string name="settings_advanced_clear_logs_summary">Удалить ранее записанные журналы, и начать сначала</string>
<string name="settings_advanced_clear_logs_deleted_toast">Журналы удалены</string>
<string name="settings_advanced_connection_protocol_title">Протокол соединения</string>
<string name="settings_advanced_connection_protocol_summary_jsonhttp">Использовать JSON-поток через HTTP чтобы подключаться к серверу. Это надежный метод, но он может потреблять больше энергии.</string>
<string name="settings_advanced_connection_protocol_summary_ws">Использовать WebSockets для подключения к серверу. Это рекомендуемый метод, но может потребовать доплонительной настройки прокси-сервера.</string>
<string name="settings_advanced_connection_protocol_entry_jsonhttp">JSON поток поверх HTTP</string>
<string name="settings_advanced_connection_protocol_entry_ws">WebSockets</string>
<string name="settings_about_header">О программе</string>
<string name="settings_about_version_title">Версия</string>
<string name="settings_about_version_format">ntfy %1$s (%2$s)</string>
<string name="settings_about_version_copied_to_clipboard_message">Скопировано в буфер обмена</string>
<string name="user_dialog_title_add">Добавить пользователя</string>
<string name="user_dialog_title_edit">Редактировать пользователя</string>
<string name="user_dialog_description_add">Вы можете добавить здесь пользователя. Все темы на заданном сервере будут использовать этого пользователя.</string>
<string name="settings_general_users_prefs_user_used_by_many">Использован темами %1$s</string>
<string name="settings_general_dark_mode_title">Тёмная тема</string>
<string name="settings_general_dark_mode_summary_system">Используются системные настройки по умолчанию</string>
<string name="settings_general_dark_mode_summary_light">Светлая тема включена</string>
<string name="settings_general_dark_mode_summary_dark">Тёмная тема включена. Вы вампир\?</string>
<string name="settings_general_dark_mode_entry_system">Использовать системные настройки по умолчанию</string>
<string name="settings_general_dark_mode_entry_light">Светлая тема</string>
<string name="settings_general_dark_mode_entry_dark">Тёмная тема</string>
<string name="settings_backup_restore_header">Резервное копирование</string>
<string name="settings_backup_restore_backup_title">Сохранить настройки в файл</string>
<string name="settings_backup_restore_backup_summary">Экспортировать настройки, уведомления и пользователей</string>
<string name="settings_backup_restore_backup_entry_everything">Всё</string>
<string name="settings_backup_restore_backup_entry_everything_no_users">Всё, кроме пользователей</string>
<string name="settings_backup_restore_backup_entry_settings_only">Только настройки</string>
<string name="settings_backup_restore_backup_successful">Создана резервная копия</string>
<string name="settings_backup_restore_backup_failed">Резервное копирование провалено: %1$s</string>
<string name="settings_backup_restore_restore_summary">Импортировать настройки, уведомления и пользователей</string>
<string name="settings_backup_restore_restore_successful">Восстановление успешно завершено</string>
<string name="settings_backup_restore_restore_failed">Восстановление провалено: %1$s</string>
<string name="settings_advanced_header">Дополнительно</string>
<string name="settings_advanced_broadcast_title">Вещать сообщения</string>
<string name="settings_advanced_broadcast_summary_disabled">Приложения не могут получать уведомления как вещания</string>
<string name="settings_advanced_record_logs_title">Записывать журналы</string>
<string name="settings_advanced_record_logs_summary_disabled">Включить журналирование, чтобы вы могли поделиться журналами позже для диагностики неполадок.</string>
<string name="settings_advanced_export_logs_title">Скопировать/загрузить журналы</string>
<string name="settings_advanced_export_logs_entry_copy_scrubbed">Скопировать в буфер обмена (с цензурой)</string>
<string name="settings_advanced_export_logs_entry_upload_original">Загрузить, и скопировать ссылку</string>
<string name="settings_advanced_export_logs_entry_upload_scrubbed">Загрузить, и скопировать ссылку (с цензурой)</string>
<string name="user_dialog_description_edit">Вы можете изменить имя или пароль выбранного пользователя, или удалить его.</string>
<string name="user_dialog_base_url_hint">Базовый URL службы</string>
<string name="user_dialog_password_hint_add">Пароль</string>
<string name="user_dialog_password_hint_edit">Пароль (не изменится если оставить пустым)</string>
<string name="user_dialog_button_add">Добавить пользователя</string>
<string name="user_dialog_button_cancel">Отмена</string>
<string name="user_dialog_button_delete">Удалить пользователя</string>
<string name="notification_popup_user_action_failed">%1$s не удалась: %2$s</string>
<string name="channel_subscriber_notification_instant_text_five">Подписан на пять тем с мгновенной доставкой</string>
<string name="channel_subscriber_notification_instant_text_six">Подписан на шесть тем с мгновенной доставкой</string>
<string name="channel_subscriber_notification_noinstant_text_five">Подписан на пять тем</string>
<string name="channel_subscriber_notification_noinstant_text_six">Подписан на шесть тем</string>
<string name="main_banner_websocket_button_enable_now">Включить сейчас</string>
<string name="detail_settings_notifications_instant_summary_on">Уведомления доставляются сразу. Требует forground сервис и потребляет больше энергии.</string>
<string name="settings_notifications_insistent_max_priority_summary_enabled">Уведомления с наивысшим приоритетом будут требовать внимания пока не будут прочтены</string>
<string name="channel_notifications_group_default_name">По умолчанию</string>
<string name="detail_item_cannot_open_apk">Установка приложений через уведомления больше не поддерживается. Скачайте приложение через браузер. Подробности смотрите в отчете ntfy #531.</string>
<string name="detail_settings_appearance_icon_set_title">Иконка подписки</string>
<string name="detail_settings_appearance_icon_set_summary">Использовать иконку для отображения в уведомлениях</string>
<string name="main_menu_donate_title">Пожертвовать 💸</string>
<string name="settings_notifications_insistent_max_priority_summary_disabled">Уведомления с наивысшим приориетом будут давать о себе знать только один раз</string>
<string name="detail_settings_notifications_instant_summary_off">Уведомления будут доставляться с помощью Firebase. Могут быть задержки с доставкой, но потребляет меньше энергии.</string>
<string name="add_dialog_base_urls_dropdown_clear">Очистить URL-адрес сервера</string>
<string name="detail_settings_appearance_header">Внешний вид</string>
<string name="detail_settings_appearance_icon_error_saving">Невозможно сохранить иконку: %1$s</string>
<string name="detail_settings_appearance_display_name_title">Псевдоним</string>
<string name="detail_settings_global_setting_suffix">испольует глобальное значение</string>
<string name="detail_settings_appearance_display_name_message">Выставить произвольный псевдоним для этой подписки. Оставьте пустым чтобы использовать значение по умолчанию (%1$s).</string>
<string name="detail_settings_appearance_display_name_default_summary">%1$s (по умолчанию)</string>
<string name="detail_settings_about_topic_url_copied_to_clipboard_message">Скопирован в буфер обмена</string>
<string name="detail_settings_notifications_instant_title">Мгновенная доставка</string>
<string name="detail_settings_notifications_dedicated_channels_title">Пользовательские настройки уведомлений</string>
<string name="detail_settings_notifications_open_channels_title">Настройки уведомлений</string>
<string name="settings_advanced_unifiedpush_title">Включить UnifiedPush</string>
<string name="detail_settings_about_header">Настройки темы</string>
<string name="detail_settings_notifications_dedicated_channels_summary_off">Используются настройки по умолчанию (звуки, игнорирование режима \"не беспокоить\", и прочее)</string>
<string name="settings_advanced_unifiedpush_summary_enabled">ntfy будет действовать как сервис доставки UnifiedPush</string>
<string name="detail_settings_about_topic_url_title">URL-адрес темы</string>
<string name="settings_advanced_unifiedpush_summary_disabled">ntfy не будет действовать как сервис доставки UnifiedPush</string>
<string name="detail_settings_appearance_icon_remove_summary">Иконка используемая в уведомлениях от этой темы</string>
<string name="detail_settings_global_setting_title">Использовать глобальное значение</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_enabled">Продолжать уведомлять</string>
<string name="main_banner_websocket_text">Мы рекомендуем использовать WebSockets для подключения к Вашему серверу; это может продлить время работы от батареи, но может потребовать <a href="https://ntfy.sh/docs/config/#nginxapache2caddy">дополнительной настройки прокси-сервера</a>. Эта опция может быть включена или выключена в Настройках.</string>
<string name="detail_settings_appearance_icon_remove_title">Иконка подписки (коснитесь, чтобы удалить)</string>
<string name="add_dialog_base_urls_dropdown_choose">Выберите URL-адрес сервера</string>
<string name="detail_settings_notifications_open_channels_summary">Игнорирование режима \"не беспокоить\", звуки и прочее.</string>
<string name="detail_settings_notifications_dedicated_channels_summary_on">Используются пользовательские настройки для этой подписки</string>
<string name="detail_settings_notifications_insistent_max_priority_list_item_disabled">Уведомлять только один раз</string>
<string name="settings_notifications_insistent_max_priority_title">Продолжать уведомлять при наивысшем приоритете</string>
</resources>

Some files were not shown because too many files have changed in this diff Show more