WIP: Muted until
This commit is contained in:
parent
0c6f1cd540
commit
71b5d56f6a
17 changed files with 479 additions and 42 deletions
|
@ -58,6 +58,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"
|
||||||
|
|
118
app/schemas/io.heckel.ntfy.data.Database/3.json
Normal file
118
app/schemas/io.heckel.ntfy.data.Database/3.json
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
{
|
||||||
|
"formatVersion": 1,
|
||||||
|
"database": {
|
||||||
|
"version": 3,
|
||||||
|
"identityHash": "7b0ef556331f6d2dd3515425837c3d3a",
|
||||||
|
"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, 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
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"autoGenerate": false
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_Subscription_baseUrl_topic",
|
||||||
|
"unique": true,
|
||||||
|
"columnNames": [
|
||||||
|
"baseUrl",
|
||||||
|
"topic"
|
||||||
|
],
|
||||||
|
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Subscription_baseUrl_topic` ON `${TABLE_NAME}` (`baseUrl`, `topic`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Notification",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `message` TEXT NOT NULL, `notificationId` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, PRIMARY KEY(`id`))",
|
||||||
|
"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": "message",
|
||||||
|
"columnName": "message",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "notificationId",
|
||||||
|
"columnName": "notificationId",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "deleted",
|
||||||
|
"columnName": "deleted",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"autoGenerate": false
|
||||||
|
},
|
||||||
|
"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, '7b0ef556331f6d2dd3515425837c3d3a')"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,15 +7,11 @@
|
||||||
- WAKE_LOCK & RECEIVE_BOOT_COMPLETED are required to restart the foreground service
|
- WAKE_LOCK & RECEIVE_BOOT_COMPLETED are required to restart the foreground service
|
||||||
if it is stopped; see https://robertohuertas.com/2019/06/29/android_foreground_services/
|
if it is stopped; see https://robertohuertas.com/2019/06/29/android_foreground_services/
|
||||||
-->
|
-->
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<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"/>
|
||||||
|
|
||||||
<!--
|
|
||||||
Application
|
|
||||||
- usesCleartextTraffic is required to support "use another server" feature
|
|
||||||
-->
|
|
||||||
<application
|
<application
|
||||||
android:name=".app.Application"
|
android:name=".app.Application"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
@ -25,7 +21,8 @@
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
android:usesCleartextTraffic="true">
|
android:usesCleartextTraffic="true">
|
||||||
|
<activity android:name=".ui.SubscriptionSettingsActivity">
|
||||||
|
</activity>
|
||||||
<!-- Main activity -->
|
<!-- Main activity -->
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.MainActivity"
|
android:name=".ui.MainActivity"
|
||||||
|
@ -35,28 +32,22 @@
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity> <!-- Detail activity -->
|
||||||
|
|
||||||
<!-- Detail activity -->
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.DetailActivity"
|
android:name=".ui.DetailActivity"
|
||||||
android:parentActivityName=".ui.MainActivity">
|
android:parentActivityName=".ui.MainActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".ui.MainActivity" />
|
android:value=".ui.MainActivity"/>
|
||||||
</activity>
|
</activity> <!-- Subscriber foreground service for hosts other than ntfy.sh -->
|
||||||
|
<service android:name=".msg.SubscriberService"/> <!-- Subscriber service restart on reboot -->
|
||||||
<!-- Subscriber foreground service for hosts other than ntfy.sh -->
|
<receiver
|
||||||
<service android:name=".msg.SubscriberService" />
|
android:name=".msg.SubscriberService$StartReceiver"
|
||||||
|
android:enabled="true">
|
||||||
<!-- Subscriber service restart on reboot -->
|
|
||||||
<receiver android:enabled="true" android:name=".msg.SubscriberService$StartReceiver">
|
|
||||||
<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> <!-- Firebase messaging -->
|
||||||
|
|
||||||
<!-- Firebase messaging -->
|
|
||||||
<service
|
<service
|
||||||
android:name=".msg.FirebaseService"
|
android:name=".msg.FirebaseService"
|
||||||
android:exported="false">
|
android:exported="false">
|
||||||
|
|
|
@ -5,6 +5,7 @@ import androidx.room.*
|
||||||
import androidx.room.migration.Migration
|
import androidx.room.migration.Migration
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
@Entity(indices = [Index(value = ["baseUrl", "topic"], unique = true)])
|
@Entity(indices = [Index(value = ["baseUrl", "topic"], unique = true)])
|
||||||
data class Subscription(
|
data class Subscription(
|
||||||
|
@ -12,12 +13,16 @@ data class Subscription(
|
||||||
@ColumnInfo(name = "baseUrl") val baseUrl: String,
|
@ColumnInfo(name = "baseUrl") val baseUrl: String,
|
||||||
@ColumnInfo(name = "topic") val topic: String,
|
@ColumnInfo(name = "topic") val topic: String,
|
||||||
@ColumnInfo(name = "instant") val instant: Boolean,
|
@ColumnInfo(name = "instant") val instant: Boolean,
|
||||||
|
@ColumnInfo(name = "mutedUntil") val mutedUntil: Long,
|
||||||
|
//val notificationSchedule: String,
|
||||||
|
//val notificationSound: String,
|
||||||
@Ignore val totalCount: Int = 0, // Total notifications
|
@Ignore val totalCount: Int = 0, // Total notifications
|
||||||
@Ignore val newCount: Int = 0, // New notifications
|
@Ignore val newCount: Int = 0, // New notifications
|
||||||
@Ignore val lastActive: Long = 0, // Unix timestamp
|
@Ignore val lastActive: Long = 0, // Unix timestamp
|
||||||
@Ignore val state: ConnectionState = ConnectionState.NOT_APPLICABLE
|
@Ignore val state: ConnectionState = ConnectionState.NOT_APPLICABLE
|
||||||
) {
|
) {
|
||||||
constructor(id: Long, baseUrl: String, topic: String, instant: Boolean) : this(id, baseUrl, topic, instant, 0, 0, 0, ConnectionState.NOT_APPLICABLE)
|
constructor(id: Long, baseUrl: String, topic: String, instant: Boolean, mutedUntil: Long) :
|
||||||
|
this(id, baseUrl, topic, instant, mutedUntil, 0, 0, 0, ConnectionState.NOT_APPLICABLE)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class ConnectionState {
|
enum class ConnectionState {
|
||||||
|
@ -29,6 +34,7 @@ data class SubscriptionWithMetadata(
|
||||||
val baseUrl: String,
|
val baseUrl: String,
|
||||||
val topic: String,
|
val topic: String,
|
||||||
val instant: Boolean,
|
val instant: Boolean,
|
||||||
|
val mutedUntil: Long,
|
||||||
val totalCount: Int,
|
val totalCount: Int,
|
||||||
val newCount: Int,
|
val newCount: Int,
|
||||||
val lastActive: Long
|
val lastActive: Long
|
||||||
|
@ -44,7 +50,7 @@ data class Notification(
|
||||||
@ColumnInfo(name = "deleted") val deleted: Boolean,
|
@ColumnInfo(name = "deleted") val deleted: Boolean,
|
||||||
)
|
)
|
||||||
|
|
||||||
@androidx.room.Database(entities = [Subscription::class, Notification::class], version = 2)
|
@androidx.room.Database(entities = [Subscription::class, Notification::class], version = 3)
|
||||||
abstract class Database : RoomDatabase() {
|
abstract class Database : RoomDatabase() {
|
||||||
abstract fun subscriptionDao(): SubscriptionDao
|
abstract fun subscriptionDao(): SubscriptionDao
|
||||||
abstract fun notificationDao(): NotificationDao
|
abstract fun notificationDao(): NotificationDao
|
||||||
|
@ -79,6 +85,12 @@ abstract class Database : RoomDatabase() {
|
||||||
db.execSQL("ALTER TABLE Notification ADD COLUMN deleted INTEGER NOT NULL DEFAULT('0')")
|
db.execSQL("ALTER TABLE Notification ADD COLUMN deleted INTEGER NOT NULL DEFAULT('0')")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val MIGRATION_2_3 = object : Migration(2, 3) {
|
||||||
|
override fun migrate(db: SupportSQLiteDatabase) {
|
||||||
|
db.execSQL("ALTER TABLE Subscription ADD COLUMN mutedUntil INTEGER NOT NULL DEFAULT('0')")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +98,7 @@ abstract class Database : RoomDatabase() {
|
||||||
interface SubscriptionDao {
|
interface SubscriptionDao {
|
||||||
@Query("""
|
@Query("""
|
||||||
SELECT
|
SELECT
|
||||||
s.id, s.baseUrl, s.topic, s.instant,
|
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil,
|
||||||
COUNT(n.id) totalCount,
|
COUNT(n.id) totalCount,
|
||||||
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
|
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
|
||||||
IFNULL(MAX(n.timestamp),0) AS lastActive
|
IFNULL(MAX(n.timestamp),0) AS lastActive
|
||||||
|
@ -99,7 +111,7 @@ interface SubscriptionDao {
|
||||||
|
|
||||||
@Query("""
|
@Query("""
|
||||||
SELECT
|
SELECT
|
||||||
s.id, s.baseUrl, s.topic, s.instant,
|
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil,
|
||||||
COUNT(n.id) totalCount,
|
COUNT(n.id) totalCount,
|
||||||
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
|
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
|
||||||
IFNULL(MAX(n.timestamp),0) AS lastActive
|
IFNULL(MAX(n.timestamp),0) AS lastActive
|
||||||
|
@ -112,7 +124,7 @@ interface SubscriptionDao {
|
||||||
|
|
||||||
@Query("""
|
@Query("""
|
||||||
SELECT
|
SELECT
|
||||||
s.id, s.baseUrl, s.topic, s.instant,
|
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil,
|
||||||
COUNT(n.id) totalCount,
|
COUNT(n.id) totalCount,
|
||||||
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
|
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
|
||||||
IFNULL(MAX(n.timestamp),0) AS lastActive
|
IFNULL(MAX(n.timestamp),0) AS lastActive
|
||||||
|
@ -125,7 +137,7 @@ interface SubscriptionDao {
|
||||||
|
|
||||||
@Query("""
|
@Query("""
|
||||||
SELECT
|
SELECT
|
||||||
s.id, s.baseUrl, s.topic, s.instant,
|
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil,
|
||||||
COUNT(n.id) totalCount,
|
COUNT(n.id) totalCount,
|
||||||
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
|
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
|
||||||
IFNULL(MAX(n.timestamp),0) AS lastActive
|
IFNULL(MAX(n.timestamp),0) AS lastActive
|
||||||
|
|
|
@ -113,6 +113,7 @@ class Repository(private val subscriptionDao: SubscriptionDao, private val notif
|
||||||
baseUrl = s.baseUrl,
|
baseUrl = s.baseUrl,
|
||||||
topic = s.topic,
|
topic = s.topic,
|
||||||
instant = s.instant,
|
instant = s.instant,
|
||||||
|
mutedUntil = s.mutedUntil,
|
||||||
totalCount = s.totalCount,
|
totalCount = s.totalCount,
|
||||||
newCount = s.newCount,
|
newCount = s.newCount,
|
||||||
lastActive = s.lastActive,
|
lastActive = s.lastActive,
|
||||||
|
@ -130,6 +131,7 @@ class Repository(private val subscriptionDao: SubscriptionDao, private val notif
|
||||||
baseUrl = s.baseUrl,
|
baseUrl = s.baseUrl,
|
||||||
topic = s.topic,
|
topic = s.topic,
|
||||||
instant = s.instant,
|
instant = s.instant,
|
||||||
|
mutedUntil = s.mutedUntil,
|
||||||
totalCount = s.totalCount,
|
totalCount = s.totalCount,
|
||||||
newCount = s.newCount,
|
newCount = s.newCount,
|
||||||
lastActive = s.lastActive,
|
lastActive = s.lastActive,
|
||||||
|
|
|
@ -33,7 +33,7 @@ import kotlinx.coroutines.launch
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.atomic.AtomicLong
|
import java.util.concurrent.atomic.AtomicLong
|
||||||
|
|
||||||
class DetailActivity : AppCompatActivity(), ActionMode.Callback {
|
class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFragment.NotificationSettingsListener {
|
||||||
private val viewModel by viewModels<DetailViewModel> {
|
private val viewModel by viewModels<DetailViewModel> {
|
||||||
DetailViewModelFactory((application as Application).repository)
|
DetailViewModelFactory((application as Application).repository)
|
||||||
}
|
}
|
||||||
|
@ -187,6 +187,10 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback {
|
||||||
onTestClick()
|
onTestClick()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
R.id.detail_menu_notification -> {
|
||||||
|
onNotificationSettingsClick()
|
||||||
|
true
|
||||||
|
}
|
||||||
R.id.detail_menu_enable_instant -> {
|
R.id.detail_menu_enable_instant -> {
|
||||||
onInstantEnableClick(enable = true)
|
onInstantEnableClick(enable = true)
|
||||||
true
|
true
|
||||||
|
@ -228,6 +232,38 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun onNotificationSettingsClick() {
|
||||||
|
Log.d(TAG, "Showing notification settings dialog for ${topicShortUrl(subscriptionBaseUrl, subscriptionTopic)}")
|
||||||
|
val intent = Intent(this, SubscriptionSettingsActivity::class.java)
|
||||||
|
startActivityForResult(intent, /*XXXXXX*/MainActivity.REQUEST_CODE_DELETE_SUBSCRIPTION)
|
||||||
|
/*
|
||||||
|
val notificationFragment = NotificationFragment()
|
||||||
|
notificationFragment.show(supportFragmentManager, NotificationFragment.TAG)*/
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNotificationSettingsChanged(mutedUntil: Long) {
|
||||||
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
val subscription = repository.getSubscription(subscriptionId)
|
||||||
|
val newSubscription = subscription?.copy(mutedUntil = mutedUntil)
|
||||||
|
newSubscription?.let { repository.updateSubscription(newSubscription) }
|
||||||
|
runOnUiThread {
|
||||||
|
when (mutedUntil) {
|
||||||
|
0L -> Toast.makeText(this@DetailActivity, getString(R.string.notification_dialog_enabled_toast_message), Toast.LENGTH_SHORT).show()
|
||||||
|
1L -> Toast.makeText(this@DetailActivity, getString(R.string.notification_dialog_muted_forever_toast_message), Toast.LENGTH_SHORT).show()
|
||||||
|
else -> {
|
||||||
|
val mutedUntilDate = Date(mutedUntil).toString()
|
||||||
|
Toast.makeText(
|
||||||
|
this@DetailActivity,
|
||||||
|
getString(R.string.notification_dialog_muted_until_toast_message, mutedUntilDate),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private fun onCopyUrlClick() {
|
private fun onCopyUrlClick() {
|
||||||
val url = topicUrl(subscriptionBaseUrl, subscriptionTopic)
|
val url = topicUrl(subscriptionBaseUrl, subscriptionTopic)
|
||||||
Log.d(TAG, "Copying topic URL $url to clipboard ")
|
Log.d(TAG, "Copying topic URL $url to clipboard ")
|
||||||
|
@ -478,6 +514,5 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "NtfyDetailActivity"
|
const val TAG = "NtfyDetailActivity"
|
||||||
const val CANCEL_NOTIFICATION_DELAY_MILLIS = 20_000L
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,6 +165,7 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
topic = topic,
|
topic = topic,
|
||||||
instant = instant,
|
instant = instant,
|
||||||
|
mutedUntil = 0,
|
||||||
totalCount = 0,
|
totalCount = 0,
|
||||||
newCount = 0,
|
newCount = 0,
|
||||||
lastActive = Date().time/1000
|
lastActive = Date().time/1000
|
||||||
|
|
73
app/src/main/java/io/heckel/ntfy/ui/NotificationFragment.kt
Normal file
73
app/src/main/java/io/heckel/ntfy/ui/NotificationFragment.kt
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
package io.heckel.ntfy.ui
|
||||||
|
|
||||||
|
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.util.Log
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.Button
|
||||||
|
import android.widget.CheckBox
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.google.android.material.textfield.TextInputEditText
|
||||||
|
import io.heckel.ntfy.R
|
||||||
|
import io.heckel.ntfy.data.Database
|
||||||
|
import io.heckel.ntfy.data.Repository
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class NotificationFragment : DialogFragment() {
|
||||||
|
private lateinit var repository: Repository
|
||||||
|
private lateinit var settingsListener: NotificationSettingsListener
|
||||||
|
|
||||||
|
interface NotificationSettingsListener {
|
||||||
|
fun onNotificationSettingsChanged(mutedUntil: Long)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAttach(context: Context) {
|
||||||
|
super.onAttach(context)
|
||||||
|
settingsListener = activity as NotificationSettingsListener
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
if (activity == null) {
|
||||||
|
throw IllegalStateException("Activity cannot be null")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dependencies
|
||||||
|
val database = Database.getInstance(activity!!.applicationContext)
|
||||||
|
repository = Repository.getInstance(database.subscriptionDao(), database.notificationDao())
|
||||||
|
|
||||||
|
// Build root view
|
||||||
|
val view = requireActivity().layoutInflater.inflate(R.layout.notification_dialog_fragment, null)
|
||||||
|
// topicNameText = view.findViewById(R.id.add_dialog_topic_text) as TextInputEditText
|
||||||
|
|
||||||
|
// Build dialog
|
||||||
|
val alert = AlertDialog.Builder(activity)
|
||||||
|
.setView(view)
|
||||||
|
.setPositiveButton(R.string.notification_dialog_save) { _, _ ->
|
||||||
|
///
|
||||||
|
settingsListener.onNotificationSettingsChanged(0L)
|
||||||
|
}
|
||||||
|
.setNegativeButton(R.string.notification_dialog_cancel) { _, _ ->
|
||||||
|
dialog?.cancel()
|
||||||
|
}
|
||||||
|
.create()
|
||||||
|
|
||||||
|
// Add logic to disable "Subscribe" button on invalid input
|
||||||
|
alert.setOnShowListener {
|
||||||
|
val dialog = it as AlertDialog
|
||||||
|
///
|
||||||
|
}
|
||||||
|
|
||||||
|
return alert
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "NtfyNotificationFragment"
|
||||||
|
}
|
||||||
|
}
|
5
app/src/main/java/io/heckel/ntfy/ui/SettingsFragment.kt
Normal file
5
app/src/main/java/io/heckel/ntfy/ui/SettingsFragment.kt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
package io.heckel.ntfy.ui
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
import io.heckel.ntfy.R
|
|
@ -0,0 +1,25 @@
|
||||||
|
package io.heckel.ntfy.ui
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
import io.heckel.ntfy.R
|
||||||
|
|
||||||
|
class SubscriptionSettingsActivity : AppCompatActivity() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_subscription_settings)
|
||||||
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
|
supportActionBar?.setDisplayShowHomeEnabled(true)
|
||||||
|
supportFragmentManager
|
||||||
|
.beginTransaction()
|
||||||
|
.replace(R.id.subscription_settings_content, SubscriptionSettingsFragment())
|
||||||
|
.commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
class SubscriptionSettingsFragment : PreferenceFragmentCompat() {
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
setPreferencesFromResource(R.xml.root_preferences, rootKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.89,2 2,2zM18,16v-5c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2z"
|
||||||
|
android:fillColor="#FFFFFF"/>
|
||||||
|
</vector>
|
18
app/src/main/res/layout/activity_subscription_settings.xml
Normal file
18
app/src/main/res/layout/activity_subscription_settings.xml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".ui.SubscriptionSettingsActivity">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:id="@+id/subscription_settings_content" app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent">
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
66
app/src/main/res/layout/notification_dialog_fragment.xml
Normal file
66
app/src/main/res/layout/notification_dialog_fragment.xml
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:paddingLeft="16dp"
|
||||||
|
android:paddingRight="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/add_dialog_title_text2"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
android:paddingBottom="3dp"
|
||||||
|
android:text="@string/notification_dialog_title"
|
||||||
|
android:textAlignment="viewStart"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Large" android:paddingStart="4dp"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent"
|
||||||
|
android:layout_marginStart="16dp" android:layout_marginEnd="16dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"/>
|
||||||
|
<TextView
|
||||||
|
android:text="Pause notifications"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" android:id="@+id/textView"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/add_dialog_title_text2"
|
||||||
|
android:layout_marginTop="20dp" app:layout_constraintStart_toStartOf="@+id/add_dialog_title_text2"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium"/>
|
||||||
|
<RadioGroup
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintStart_toStartOf="@+id/textView" app:layout_constraintTop_toBottomOf="@+id/textView"
|
||||||
|
android:layout_marginTop="10dp">
|
||||||
|
<RadioButton
|
||||||
|
android:text="Pause forever"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" android:id="@+id/radioButton"
|
||||||
|
/>
|
||||||
|
<RadioButton
|
||||||
|
android:text="Pause for 30 minutes"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" android:id="@+id/radioButton4"
|
||||||
|
/>
|
||||||
|
<RadioButton
|
||||||
|
android:text="Pause for 1 hour"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" android:id="@+id/radioButton5"
|
||||||
|
/>
|
||||||
|
<RadioButton
|
||||||
|
android:text="Pause for 2 hours"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" android:id="@+id/radioButton6"
|
||||||
|
/>
|
||||||
|
<RadioButton
|
||||||
|
android:text="Pause until tomorrow"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" android:id="@+id/radioButton3"
|
||||||
|
/>
|
||||||
|
</RadioGroup>
|
||||||
|
<Switch
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" android:id="@+id/switch1"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/textView" app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:layout_marginTop="19dp" app:layout_constraintTop_toBottomOf="@+id/add_dialog_title_text2"/>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,4 +1,6 @@
|
||||||
<menu xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android" >
|
<menu xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
<item android:id="@+id/detail_menu_notification" android:title="@string/detail_menu_enable_instant"
|
||||||
|
app:showAsAction="ifRoom" android:icon="@drawable/ic_notifications_white_24dp"/>
|
||||||
<item android:id="@+id/detail_menu_enable_instant" android:title="@string/detail_menu_enable_instant"
|
<item android:id="@+id/detail_menu_enable_instant" android:title="@string/detail_menu_enable_instant"
|
||||||
app:showAsAction="ifRoom" android:icon="@drawable/ic_bolt_outline_white_24dp"/>
|
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"
|
<item android:id="@+id/detail_menu_disable_instant" android:title="@string/detail_menu_disable_instant"
|
||||||
|
|
16
app/src/main/res/values/arrays.xml
Normal file
16
app/src/main/res/values/arrays.xml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<resources>
|
||||||
|
<!-- Reply Preference -->
|
||||||
|
<string-array name="reply_entries">
|
||||||
|
<item>Forever</item>
|
||||||
|
<item>30 minutes</item>
|
||||||
|
<item>1 hour</item>
|
||||||
|
<item>2 hours</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="reply_values">
|
||||||
|
<item>forever</item>
|
||||||
|
<item>30min</item>
|
||||||
|
<item>1hr</item>
|
||||||
|
<item>2h</item>
|
||||||
|
</string-array>
|
||||||
|
</resources>
|
|
@ -10,7 +10,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>
|
||||||
|
|
||||||
|
@ -27,7 +28,9 @@
|
||||||
|
|
||||||
<!-- Main activity: Action mode -->
|
<!-- Main activity: Action mode -->
|
||||||
<string name="main_action_mode_menu_unsubscribe">Unsubscribe</string>
|
<string name="main_action_mode_menu_unsubscribe">Unsubscribe</string>
|
||||||
<string name="main_action_mode_delete_dialog_message">Do you really want to unsubscribe from selected topic(s) and permanently delete all the messages you received?</string>
|
<string name="main_action_mode_delete_dialog_message">Do you really want to unsubscribe from selected topic(s) and
|
||||||
|
permanently delete all the messages you received?
|
||||||
|
</string>
|
||||||
<string name="main_action_mode_delete_dialog_permanently_delete">Permanently delete</string>
|
<string name="main_action_mode_delete_dialog_permanently_delete">Permanently delete</string>
|
||||||
<string name="main_action_mode_delete_dialog_cancel">Cancel</string>
|
<string name="main_action_mode_delete_dialog_cancel">Cancel</string>
|
||||||
|
|
||||||
|
@ -38,12 +41,17 @@
|
||||||
<string name="main_item_date_yesterday">Yesterday</string>
|
<string name="main_item_date_yesterday">Yesterday</string>
|
||||||
<string name="main_add_button_description">Add subscription</string>
|
<string name="main_add_button_description">Add subscription</string>
|
||||||
<string name="main_no_subscriptions_text">It looks like you don\'t have any subscriptions yet.</string>
|
<string name="main_no_subscriptions_text">It looks like you don\'t have any subscriptions yet.</string>
|
||||||
<string name="main_how_to_intro">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.</string>
|
<string name="main_how_to_intro">Click the button below to create or subscribe to a topic. After that, you can send
|
||||||
<string name="main_how_to_link">For more detailed instructions, check out the ntfy.sh website and documentation.</string>
|
messages via PUT or POST and you\'ll receive notifications on your phone.
|
||||||
|
</string>
|
||||||
|
<string name="main_how_to_link">For more detailed instructions, check out the ntfy.sh website and documentation.
|
||||||
|
</string>
|
||||||
|
|
||||||
<!-- Add dialog -->
|
<!-- Add dialog -->
|
||||||
<string name="add_dialog_title">Subscribe to topic</string>
|
<string name="add_dialog_title">Subscribe to topic</string>
|
||||||
<string name="add_dialog_description_below">Topics are not password-protected, so choose a name that\'s not easy to guess. Once subscribed, you can PUT/POST to receive notifications on your phone.</string>
|
<string name="add_dialog_description_below">Topics are not password-protected, so choose a name that\'s not easy to
|
||||||
|
guess. Once subscribed, you can PUT/POST to receive notifications on your phone.
|
||||||
|
</string>
|
||||||
<string name="add_dialog_topic_name_hint">Topic name, e.g. phils_alerts</string>
|
<string name="add_dialog_topic_name_hint">Topic name, e.g. phils_alerts</string>
|
||||||
<string name="add_dialog_use_another_server">Use another server</string>
|
<string name="add_dialog_use_another_server">Use another server</string>
|
||||||
<string name="add_dialog_use_another_server_description">
|
<string name="add_dialog_use_another_server_description">
|
||||||
|
@ -60,13 +68,18 @@
|
||||||
|
|
||||||
<!-- Detail activity -->
|
<!-- Detail activity -->
|
||||||
<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_delete_dialog_message">Do you really want to unsubscribe from this topic and delete all of the messages you received?</string>
|
</string>
|
||||||
|
<string name="detail_delete_dialog_message">Do you really want to unsubscribe from this topic and delete all of the
|
||||||
|
messages you received?
|
||||||
|
</string>
|
||||||
<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_message">This is a test notification from the Ntfy Android app. It was sent at %1$s.</string>
|
<string name="detail_test_message">This is a test notification from the Ntfy Android app. It was sent at %1$s.
|
||||||
|
</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>
|
||||||
|
@ -74,17 +87,44 @@
|
||||||
<string name="detail_instant_info">Instant delivery cannot be disabled for subscriptions from other servers</string>
|
<string name="detail_instant_info">Instant delivery cannot be disabled for subscriptions from other servers</string>
|
||||||
|
|
||||||
<!-- Detail activity: Action bar -->
|
<!-- Detail activity: Action bar -->
|
||||||
<string name="detail_menu_test">Send test notification</string>
|
<string name="detail_menu_notification">Notification</string>
|
||||||
<string name="detail_menu_copy_url">Copy topic address</string>
|
|
||||||
<string name="detail_menu_enable_instant">Enable instant delivery</string>
|
<string name="detail_menu_enable_instant">Enable instant delivery</string>
|
||||||
<string name="detail_menu_disable_instant">Disable instant delivery</string>
|
<string name="detail_menu_disable_instant">Disable instant delivery</string>
|
||||||
|
<string name="detail_menu_test">Send test notification</string>
|
||||||
|
<string name="detail_menu_copy_url">Copy topic address</string>
|
||||||
<string name="detail_menu_instant_info">Instant delivery enabled</string>
|
<string name="detail_menu_instant_info">Instant delivery enabled</string>
|
||||||
<string name="detail_menu_unsubscribe">Unsubscribe</string>
|
<string name="detail_menu_unsubscribe">Unsubscribe</string>
|
||||||
|
|
||||||
<!-- Detail activity: Action mode -->
|
<!-- Detail activity: Action mode -->
|
||||||
<string name="detail_action_mode_menu_copy">Copy</string>
|
<string name="detail_action_mode_menu_copy">Copy</string>
|
||||||
<string name="detail_action_mode_menu_delete">Delete</string>
|
<string name="detail_action_mode_menu_delete">Delete</string>
|
||||||
<string name="detail_action_mode_delete_dialog_message">Do you really want to permanently delete the selected message(s)?</string>
|
<string name="detail_action_mode_delete_dialog_message">Do you really want to permanently delete the selected
|
||||||
|
message(s)?
|
||||||
|
</string>
|
||||||
<string name="detail_action_mode_delete_dialog_permanently_delete">Permanently delete</string>
|
<string name="detail_action_mode_delete_dialog_permanently_delete">Permanently delete</string>
|
||||||
<string name="detail_action_mode_delete_dialog_cancel">Cancel</string>
|
<string name="detail_action_mode_delete_dialog_cancel">Cancel</string>
|
||||||
|
|
||||||
|
<!-- Notification dialog -->
|
||||||
|
<string name="notification_dialog_title">Notification settings</string>
|
||||||
|
<string name="notification_dialog_cancel">Cancel</string>
|
||||||
|
<string name="notification_dialog_save">Save</string>
|
||||||
|
<string name="notification_dialog_enabled_toast_message">Notifications re-enabled</string>
|
||||||
|
<string name="notification_dialog_muted_forever_toast_message">Notifications are now paused</string>
|
||||||
|
<string name="notification_dialog_muted_until_toast_message">Notifications are now paused until %s</string>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Preference Titles -->
|
||||||
|
<string name="subscription_settings_notifications_header">Notifications</string>
|
||||||
|
<string name="subscription_settings_pause_title">Pause notifications</string>
|
||||||
|
<string name="subscription_settings_pause_for_title">Until …</string>
|
||||||
|
<string name="sync_header">Sync</string>
|
||||||
|
|
||||||
|
<!-- Messages Preferences -->
|
||||||
|
<string name="signature_title">Your signature</string>
|
||||||
|
|
||||||
|
<!-- Sync Preferences -->
|
||||||
|
|
||||||
|
<string name="attachment_title">Download incoming attachments</string>
|
||||||
|
<string name="attachment_summary_on">Automatically download attachments for incoming emails</string>
|
||||||
|
<string name="attachment_summary_off">Only download attachments when manually requested</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
23
app/src/main/res/xml/root_preferences.xml
Normal file
23
app/src/main/res/xml/root_preferences.xml
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<PreferenceScreen
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
app:title="@string/subscription_settings_notifications_header">
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
app:key="pause"
|
||||||
|
app:title="@string/subscription_settings_pause_title"/>
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
app:key="reply"
|
||||||
|
app:title="@string/subscription_settings_pause_for_title"
|
||||||
|
app:entries="@array/reply_entries"
|
||||||
|
app:entryValues="@array/reply_values"
|
||||||
|
app:defaultValue="false"
|
||||||
|
app:useSimpleSummaryProvider="true"
|
||||||
|
app:dependency="pause"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
</PreferenceScreen>
|
Loading…
Reference in a new issue