Preferences dialog

This commit is contained in:
Philipp Heckel 2021-12-31 01:34:25 +01:00
parent 72393ec0af
commit 2bc87013d5
13 changed files with 291 additions and 32 deletions

View file

@ -67,6 +67,7 @@ dependencies {
// WorkManager // WorkManager
implementation "androidx.work:work-runtime-ktx:2.6.0" implementation "androidx.work:work-runtime-ktx:2.6.0"
implementation 'androidx.preference:preference:1.1.1'
// Room (SQLite) // Room (SQLite)
def roomVersion = "2.3.0" def roomVersion = "2.3.0"

View file

@ -12,7 +12,7 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/> <uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE"/>
<application <application
android:name=".app.Application" android:name=".app.Application"
@ -23,6 +23,7 @@
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme" android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"> android:usesCleartextTraffic="true">
<!-- Main activity --> <!-- Main activity -->
<activity <activity
android:name=".ui.MainActivity" android:name=".ui.MainActivity"
@ -43,32 +44,51 @@
android:value=".ui.MainActivity"/> android:value=".ui.MainActivity"/>
</activity> </activity>
<!-- Settings activity -->
<activity
android:name=".ui.SettingsActivity"
android:parentActivityName=".ui.MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".ui.MainActivity"/>
</activity>
<!-- Subscriber foreground service for hosts other than ntfy.sh --> <!-- Subscriber foreground service for hosts other than ntfy.sh -->
<service android:name=".service.SubscriberService"/> <service android:name=".service.SubscriberService"/>
<!-- Subscriber service restart on reboot --> <!-- Subscriber service restart on reboot -->
<receiver android:name=".service.SubscriberService$BootStartReceiver" android:enabled="true"> <receiver
android:name=".service.SubscriberService$BootStartReceiver"
android:enabled="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/> <action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter> </intent-filter>
</receiver> </receiver>
<!-- Subscriber service restart on destruction --> <!-- Subscriber service restart on destruction -->
<receiver android:name=".service.SubscriberService$AutoRestartReceiver" android:enabled="true" <receiver
android:exported="false"/> android:name=".service.SubscriberService$AutoRestartReceiver"
android:enabled="true"
android:exported="false"/>
<!-- Broadcast receiver to send messages via intents --> <!-- Broadcast receiver to send messages via intents -->
<receiver android:name=".msg.BroadcastService$BroadcastReceiver" android:enabled="true" android:exported="true"> <receiver
android:name=".msg.BroadcastService$BroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter> <intent-filter>
<action android:name="io.heckel.ntfy.SEND_MESSAGE"/> <action android:name="io.heckel.ntfy.SEND_MESSAGE"/>
</intent-filter> </intent-filter>
</receiver> </receiver>
<!-- Broadcast receiver for UnifiedPush; must match https://github.com/UnifiedPush/UP-spec/blob/main/specifications.md --> <!-- Broadcast receiver for UnifiedPush; must match https://github.com/UnifiedPush/UP-spec/blob/main/specifications.md -->
<receiver android:name=".up.BroadcastReceiver" android:enabled="true" android:exported="true"> <receiver
android:name=".up.BroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter> <intent-filter>
<action android:name="org.unifiedpush.android.distributor.REGISTER" /> <action android:name="org.unifiedpush.android.distributor.REGISTER"/>
<action android:name="org.unifiedpush.android.distributor.UNREGISTER" /> <action android:name="org.unifiedpush.android.distributor.UNREGISTER"/>
</intent-filter> </intent-filter>
</receiver> </receiver>
@ -80,7 +100,6 @@
<action android:name="com.google.firebase.MESSAGING_EVENT"/> <action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter> </intent-filter>
</service> </service>
<meta-data <meta-data
android:name="firebase_analytics_collection_enabled" android:name="firebase_analytics_collection_enabled"
android:value="false"/> android:value="false"/>
@ -88,5 +107,4 @@
android:name="com.google.firebase.messaging.default_notification_icon" android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_notification"/> android:resource="@drawable/ic_notification"/>
</application> </application>
</manifest> </manifest>

View file

@ -4,6 +4,7 @@ import android.content.SharedPreferences
import android.util.Log import android.util.Log
import androidx.annotation.WorkerThread import androidx.annotation.WorkerThread
import androidx.lifecycle.* import androidx.lifecycle.*
import androidx.preference.PreferenceManager
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicLong import java.util.concurrent.atomic.AtomicLong
@ -142,12 +143,32 @@ class Repository(private val sharedPrefs: SharedPreferences, private val subscri
.apply() .apply()
} }
private suspend fun isMuted(subscriptionId: Long): Boolean {
if (isGlobalMuted()) { fun getUnifiedPushEnabled(): Boolean {
return true return sharedPrefs.getBoolean(SHARED_PREFS_UNIFIED_PUSH_ENABLED, true) // Enabled by default!
}
fun setUnifiedPushEnabled(enabled: Boolean) {
sharedPrefs.edit()
.putBoolean(SHARED_PREFS_UNIFIED_PUSH_ENABLED, enabled)
.apply()
}
fun getUnifiedPushBaseUrl(): String? {
return sharedPrefs.getString(SHARED_PREFS_UNIFIED_PUSH_BASE_URL, null)
}
fun setUnifiedPushBaseUrl(baseUrl: String) {
if (baseUrl == "") {
sharedPrefs
.edit()
.remove(SHARED_PREFS_UNIFIED_PUSH_BASE_URL)
.apply()
} else {
sharedPrefs.edit()
.putString(SHARED_PREFS_UNIFIED_PUSH_BASE_URL, baseUrl)
.apply()
} }
val s = getSubscription(subscriptionId) ?: return true
return s.mutedUntil == 1L || (s.mutedUntil > 1L && s.mutedUntil > System.currentTimeMillis()/1000)
} }
fun isGlobalMuted(): Boolean { fun isGlobalMuted(): Boolean {
@ -242,6 +263,8 @@ class Repository(private val sharedPrefs: SharedPreferences, private val subscri
const val SHARED_PREFS_POLL_WORKER_VERSION = "PollWorkerVersion" const val SHARED_PREFS_POLL_WORKER_VERSION = "PollWorkerVersion"
const val SHARED_PREFS_AUTO_RESTART_WORKER_VERSION = "AutoRestartWorkerVersion" const val SHARED_PREFS_AUTO_RESTART_WORKER_VERSION = "AutoRestartWorkerVersion"
const val SHARED_PREFS_MUTED_UNTIL_TIMESTAMP = "MutedUntil" const val SHARED_PREFS_MUTED_UNTIL_TIMESTAMP = "MutedUntil"
const val SHARED_PREFS_UNIFIED_PUSH_ENABLED = "UnifiedPushEnabled"
const val SHARED_PREFS_UNIFIED_PUSH_BASE_URL = "UnifiedPushBaseURL"
private const val TAG = "NtfyRepository" private const val TAG = "NtfyRepository"
private var instance: Repository? = null private var instance: Repository? = null

View file

@ -420,7 +420,6 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
val formattedDate = formatDateShort(subscriptionMutedUntil) val formattedDate = formatDateShort(subscriptionMutedUntil)
notificationsDisabledUntilItem?.title = getString(R.string.detail_menu_notifications_disabled_until, formattedDate) notificationsDisabledUntilItem?.title = getString(R.string.detail_menu_notifications_disabled_until, formattedDate)
} }
} }
} }

View file

@ -232,6 +232,10 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
onNotificationSettingsClick(enable = true) onNotificationSettingsClick(enable = true)
true true
} }
R.id.main_menu_settings -> {
startActivity(Intent(this, SettingsActivity::class.java))
true
}
R.id.main_menu_source -> { R.id.main_menu_source -> {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.main_menu_source_url)))) startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.main_menu_source_url))))
true true

View file

@ -0,0 +1,88 @@
package io.heckel.ntfy.ui
import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.*
import io.heckel.ntfy.BuildConfig
import io.heckel.ntfy.R
import io.heckel.ntfy.app.Application
import io.heckel.ntfy.data.Repository
class SettingsActivity : AppCompatActivity() {
private val repository by lazy { (application as Application).repository }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings)
Log.d(MainActivity.TAG, "Create $this")
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
.replace(R.id.settings_layout, SettingsFragment(repository))
.commit()
}
// Action bar
title = getString(R.string.settings_title)
// Show 'Back' button
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
class SettingsFragment(val repository: Repository) : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.main_preferences, rootKey)
// UnifiedPush Enabled
val upEnabledPrefId = context?.getString(R.string.pref_unified_push_enabled) ?: return
val upEnabled: SwitchPreference? = findPreference(upEnabledPrefId)
upEnabled?.isChecked = repository.getUnifiedPushEnabled()
upEnabled?.preferenceDataStore = object : PreferenceDataStore() {
override fun putBoolean(key: String?, value: Boolean) {
repository.setUnifiedPushEnabled(value)
}
override fun getBoolean(key: String?, defValue: Boolean): Boolean {
return repository.getUnifiedPushEnabled()
}
}
upEnabled?.summaryProvider = Preference.SummaryProvider<SwitchPreference> { pref ->
if (pref.isChecked) {
getString(R.string.settings_unified_push_enabled_summary_on)
} else {
getString(R.string.settings_unified_push_enabled_summary_off)
}
}
// UnifiedPush Base URL
val appBaseUrl = context?.getString(R.string.app_base_url) ?: return
val upBaseUrlPrefId = context?.getString(R.string.pref_unified_push_base_url) ?: return
val upBaseUrl: EditTextPreference? = findPreference(upBaseUrlPrefId)
upBaseUrl?.text = repository.getUnifiedPushBaseUrl() ?: ""
upBaseUrl?.preferenceDataStore = object : PreferenceDataStore() {
override fun putString(key: String, value: String?) {
val baseUrl = value ?: return
repository.setUnifiedPushBaseUrl(baseUrl)
}
override fun getString(key: String, defValue: String?): String? {
return repository.getUnifiedPushBaseUrl()
}
}
upBaseUrl?.summaryProvider = Preference.SummaryProvider<EditTextPreference> { pref ->
if (TextUtils.isEmpty(pref.text)) {
getString(R.string.settings_unified_push_base_url_default_summary, appBaseUrl)
} else {
pref.text
}
}
// Version
val versionPrefId = context?.getString(R.string.pref_version) ?: return
val versionPref: Preference? = findPreference(versionPrefId)
versionPref?.summary = getString(R.string.settings_about_version_format, BuildConfig.VERSION_NAME, BuildConfig.FLAVOR)
}
}
}

View file

@ -3,9 +3,9 @@ package io.heckel.ntfy.up
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.util.Log import android.util.Log
import androidx.preference.PreferenceManager
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.app.Application import io.heckel.ntfy.app.Application
import io.heckel.ntfy.data.Repository
import io.heckel.ntfy.data.Subscription import io.heckel.ntfy.data.Subscription
import io.heckel.ntfy.service.SubscriberServiceManager import io.heckel.ntfy.service.SubscriberServiceManager
import io.heckel.ntfy.util.randomString import io.heckel.ntfy.util.randomString
@ -34,8 +34,8 @@ class BroadcastReceiver : android.content.BroadcastReceiver() {
val repository = app.repository val repository = app.repository
val distributor = Distributor(app) val distributor = Distributor(app)
Log.d(TAG, "REGISTER received for app $appId (connectorToken=$connectorToken)") Log.d(TAG, "REGISTER received for app $appId (connectorToken=$connectorToken)")
if (appId.isBlank()) { if (!repository.getUnifiedPushEnabled() || appId.isBlank()) {
Log.w(TAG, "Refusing registration: empty application") Log.w(TAG, "Refusing registration: UnifiedPush disabled or empty application")
distributor.sendRegistrationRefused(appId, connectorToken) distributor.sendRegistrationRefused(appId, connectorToken)
return return
} }
@ -54,8 +54,8 @@ class BroadcastReceiver : android.content.BroadcastReceiver() {
} }
// Add subscription // Add subscription
val baseUrl = context.getString(R.string.app_base_url) // FIXME val baseUrl = repository.getUnifiedPushBaseUrl() ?: context.getString(R.string.app_base_url)
val topic = UP_PREFIX + randomString(TOPIC_LENGTH) val topic = UP_PREFIX + randomString(TOPIC_RANDOM_ID_LENGTH)
val endpoint = topicUrlUp(baseUrl, topic) val endpoint = topicUrlUp(baseUrl, topic)
val subscription = Subscription( val subscription = Subscription(
id = Random.nextLong(), id = Random.nextLong(),
@ -105,6 +105,6 @@ class BroadcastReceiver : android.content.BroadcastReceiver() {
companion object { companion object {
private const val TAG = "NtfyUpBroadcastRecv" private const val TAG = "NtfyUpBroadcastRecv"
private const val UP_PREFIX = "up" private const val UP_PREFIX = "up"
private const val TOPIC_LENGTH = 16 private const val TOPIC_RANDOM_ID_LENGTH = 12
} }
} }

View file

@ -0,0 +1,9 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/settings_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>

View file

@ -24,12 +24,13 @@
android:textColor="@color/primaryTextColor" android:layout_marginTop="10dp" android:textColor="@color/primaryTextColor" android:layout_marginTop="10dp"
app:layout_constraintEnd_toStartOf="@+id/main_item_instant_image"/> app:layout_constraintEnd_toStartOf="@+id/main_item_instant_image"/>
<TextView <TextView
android:text="89 notifications" android:text="89 notifications, reconnecting ... This may wrap in the case of UnifiedPush"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="wrap_content" android:id="@+id/main_item_status" android:layout_height="wrap_content" android:id="@+id/main_item_status"
app:layout_constraintStart_toStartOf="@+id/main_item_text" app:layout_constraintStart_toStartOf="@+id/main_item_text"
app:layout_constraintTop_toBottomOf="@+id/main_item_text" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toBottomOf="@+id/main_item_text" app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="10dp"/> android:layout_marginBottom="10dp" app:layout_constrainedWidth="true"
app:layout_constraintEnd_toStartOf="@id/main_item_new" android:layout_marginEnd="10dp"/>
<ImageView <ImageView
android:layout_width="20dp" android:layout_width="20dp"
android:layout_height="24dp" app:srcCompat="@drawable/ic_notifications_off_time_gray_outline_24dp" android:layout_height="24dp" app:srcCompat="@drawable/ic_notifications_off_time_gray_outline_24dp"

View file

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This is a slightly edited copy of the original Android project layout
to make wrapping the summary line work.
~ Copyright (C) 2015 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingRight="?android:attr/listPreferredItemPaddingRight"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:background="?android:attr/selectableItemBackground"
android:baselineAligned="false"
android:layout_marginTop="16dp"
android:gravity="center_vertical">
<include layout="@layout/image_frame"/>
<RelativeLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingTop="8dp"
android:paddingBottom="8dp">
<TextView
android:id="@android:id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:textAlignment="viewStart"
style="@style/PreferenceCategoryTitleTextStyle"/>
<!-- EDITED singleLine -->
<TextView
android:id="@android:id/summary"
android:ellipsize="end"
android:singleLine="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@android:id/title"
android:layout_alignLeft="@android:id/title"
android:layout_alignStart="@android:id/title"
android:layout_gravity="start"
android:textAlignment="viewStart"
android:textColor="?android:attr/textColorSecondary"
android:maxLines="10"
style="@style/PreferenceSummaryTextStyle"/>
</RelativeLayout>
</LinearLayout>

View file

@ -5,6 +5,7 @@
app:showAsAction="ifRoom" android:icon="@drawable/ic_notifications_off_time_white_outline_24dp"/> app:showAsAction="ifRoom" android:icon="@drawable/ic_notifications_off_time_white_outline_24dp"/>
<item android:id="@+id/main_menu_notifications_disabled_forever" android:title="@string/detail_menu_notifications_disabled_forever" <item android:id="@+id/main_menu_notifications_disabled_forever" android:title="@string/detail_menu_notifications_disabled_forever"
app:showAsAction="ifRoom" android:icon="@drawable/ic_notifications_off_white_outline_24dp"/> app:showAsAction="ifRoom" android:icon="@drawable/ic_notifications_off_white_outline_24dp"/>
<item android:id="@+id/main_menu_settings" android:title="@string/main_menu_settings_title"/>
<item android:id="@+id/main_menu_source" android:title="@string/main_menu_source_title"/> <item android:id="@+id/main_menu_source" android:title="@string/main_menu_source_title"/>
<item android:id="@+id/main_menu_website" android:title="@string/main_menu_website_title"/> <item android:id="@+id/main_menu_website" android:title="@string/main_menu_website_title"/>
</menu> </menu>

View file

@ -16,7 +16,8 @@
<string name="channel_subscriber_notification_text">You are subscribed to instant delivery topics</string> <string name="channel_subscriber_notification_text">You are subscribed to instant delivery topics</string>
<string name="channel_subscriber_notification_text_one">You are subscribed to one instant delivery topic</string> <string name="channel_subscriber_notification_text_one">You are subscribed to one instant delivery topic</string>
<string name="channel_subscriber_notification_text_two">You are subscribed to two instant delivery topics</string> <string name="channel_subscriber_notification_text_two">You are subscribed to two instant delivery topics</string>
<string name="channel_subscriber_notification_text_three">You are subscribed to three instant delivery topics</string> <string name="channel_subscriber_notification_text_three">You are subscribed to three instant delivery topics
</string>
<string name="channel_subscriber_notification_text_four">You are subscribed to four instant delivery topics</string> <string name="channel_subscriber_notification_text_four">You are subscribed to four instant delivery topics</string>
<string name="channel_subscriber_notification_text_more">You are subscribed to %1$d instant delivery topics</string> <string name="channel_subscriber_notification_text_more">You are subscribed to %1$d instant delivery topics</string>
@ -30,6 +31,7 @@
<string name="main_menu_notifications_enabled">Notifications enabled</string> <string name="main_menu_notifications_enabled">Notifications enabled</string>
<string name="main_menu_notifications_disabled_forever">Notifications disabled</string> <string name="main_menu_notifications_disabled_forever">Notifications disabled</string>
<string name="main_menu_notifications_disabled_until">Notifications disabled until %1$s</string> <string name="main_menu_notifications_disabled_until">Notifications disabled until %1$s</string>
<string name="main_menu_settings_title">Settings</string>
<string name="main_menu_source_title">Report a bug</string> <string name="main_menu_source_title">Report a bug</string>
<string name="main_menu_source_url">https://heckel.io/ntfy-android</string> <string name="main_menu_source_url">https://heckel.io/ntfy-android</string>
<string name="main_menu_website_title">Visit ntfy.sh</string> <string name="main_menu_website_title">Visit ntfy.sh</string>
@ -55,7 +57,8 @@
Click the button below to create or subscribe to a topic. After that, you can send Click the button below to create or subscribe to a topic. After that, you can send
messages via PUT or POST and you\'ll receive notifications on your phone. messages via PUT or POST and you\'ll receive notifications on your phone.
</string> </string>
<string name="main_how_to_link">For more detailed instructions, check out the ntfy.sh website and documentation.</string> <string name="main_how_to_link">For more detailed instructions, check out the ntfy.sh website and documentation.
</string>
<string name="main_unified_push_toast">This subscription is managed by %1$s via UnifiedPush</string> <string name="main_unified_push_toast">This subscription is managed by %1$s via UnifiedPush</string>
<!-- Add dialog --> <!-- Add dialog -->
@ -81,10 +84,13 @@
<!-- Detail activity --> <!-- Detail activity -->
<string name="detail_deep_link_subscribed_toast_message">Subscribed to topic %1$s</string> <string name="detail_deep_link_subscribed_toast_message">Subscribed to topic %1$s</string>
<string name="detail_no_notifications_text">You haven\'t received any notifications for this topic yet.</string> <string name="detail_no_notifications_text">You haven\'t received any notifications for this topic yet.</string>
<string name="detail_how_to_intro">To send notifications to this topic, simply PUT or POST to the topic URL.</string> <string name="detail_how_to_intro">To send notifications to this topic, simply PUT or POST to the topic URL.
</string>
<string name="detail_how_to_example"><![CDATA[ Example (using curl):<br/><tt>$ curl -d \"Hi\" %1$s</tt> ]]></string> <string name="detail_how_to_example"><![CDATA[ Example (using curl):<br/><tt>$ curl -d \"Hi\" %1$s</tt> ]]></string>
<string name="detail_how_to_link">For more detailed instructions, check out the ntfy.sh website and documentation.</string> <string name="detail_how_to_link">For more detailed instructions, check out the ntfy.sh website and documentation.
<string name="detail_clear_dialog_message">Do you really want to delete all of the notifications in this topic?</string> </string>
<string name="detail_clear_dialog_message">Do you really want to delete all of the notifications in this topic?
</string>
<string name="detail_clear_dialog_permanently_delete">Permanently delete</string> <string name="detail_clear_dialog_permanently_delete">Permanently delete</string>
<string name="detail_clear_dialog_cancel">Cancel</string> <string name="detail_clear_dialog_cancel">Cancel</string>
<string name="detail_delete_dialog_message"> <string name="detail_delete_dialog_message">
@ -94,7 +100,9 @@
<string name="detail_delete_dialog_permanently_delete">Permanently delete</string> <string name="detail_delete_dialog_permanently_delete">Permanently delete</string>
<string name="detail_delete_dialog_cancel">Cancel</string> <string name="detail_delete_dialog_cancel">Cancel</string>
<string name="detail_test_title">Test: You can set a title if you like</string> <string name="detail_test_title">Test: You can set a title if you like</string>
<string name="detail_test_message">This is a test notification from the Ntfy Android app. It has a priority of %1$d. If you send another one, it may look different.</string> <string name="detail_test_message">This is a test notification from the Ntfy Android app. It has a priority of %1$d.
If you send another one, it may look different.
</string>
<string name="detail_test_message_error">Could not send test message: %1$s</string> <string name="detail_test_message_error">Could not send test message: %1$s</string>
<string name="detail_copied_to_clipboard_message">Copied to clipboard</string> <string name="detail_copied_to_clipboard_message">Copied to clipboard</string>
<string name="detail_instant_delivery_enabled">Instant delivery enabled</string> <string name="detail_instant_delivery_enabled">Instant delivery enabled</string>
@ -136,4 +144,22 @@
<string name="notification_dialog_8h">8 hours</string> <string name="notification_dialog_8h">8 hours</string>
<string name="notification_dialog_tomorrow">Until tomorrow</string> <string name="notification_dialog_tomorrow">Until tomorrow</string>
<string name="notification_dialog_forever">Forever</string> <string name="notification_dialog_forever">Forever</string>
<!-- Settings -->
<string name="settings_title">Settings</string>
<string name="settings_unified_push_header">UnifiedPush</string>
<string name="settings_unified_push_header_summary">Allows other apps to use ntfy as a message distributor. Find out more at unifiedpush.org.</string>
<string name="settings_unified_push_enabled_title">Enabled</string>
<string name="settings_unified_push_enabled_summary_on">Apps can use ntfy as distributor</string>
<string name="settings_unified_push_enabled_summary_off">Apps cannot use ntfy as distributor</string>
<string name="settings_unified_push_base_url_title">Server URL</string>
<string name="settings_unified_push_base_url_default_summary">%1$s (default)</string>
<string name="settings_about_header">About</string>
<string name="settings_about_version">Version</string>
<string name="settings_about_version_format">ntfy %1$s (%2$s)</string>
<!-- Preferences IDs -->
<string name="pref_unified_push_enabled">UnifiedPushEnabled</string>
<string name="pref_unified_push_base_url">UnifiedPushBaseURL</string>
<string name="pref_version">Version</string>
</resources> </resources>

View file

@ -0,0 +1,21 @@
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"
app:title="@string/settings_title">
<PreferenceCategory
app:title="@string/settings_unified_push_header"
app:summary="@string/settings_unified_push_header_summary"
app:layout="@layout/preference_category_material_edited">
<SwitchPreference
app:key="@string/pref_unified_push_enabled"
app:title="@string/settings_unified_push_enabled_title"
app:enabled="true"/>
<EditTextPreference
app:key="@string/pref_unified_push_base_url"
app:title="@string/settings_unified_push_base_url_title"
app:dependency="@string/pref_unified_push_enabled"/>
</PreferenceCategory>
<PreferenceCategory app:title="@string/settings_about_header">
<Preference
app:key="@string/pref_version"
app:title="@string/settings_about_version"/>
</PreferenceCategory>
</PreferenceScreen>