custom display names

fixes binwiederhier/ntfy#313
fixes binwiederhier/ntfy#291 (at least the android portion)
This commit is contained in:
Hunter Kehoe 2022-06-24 09:15:22 -06:00
parent 6333a063a1
commit bbc7549d7a
14 changed files with 95 additions and 22 deletions

View file

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

View file

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

View file

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

View file

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

View file

@ -300,6 +300,7 @@ class NotificationService(val context: Context) {
putExtra(MainActivity.EXTRA_SUBSCRIPTION_ID, subscription.id) putExtra(MainActivity.EXTRA_SUBSCRIPTION_ID, subscription.id)
putExtra(MainActivity.EXTRA_SUBSCRIPTION_BASE_URL, subscription.baseUrl) putExtra(MainActivity.EXTRA_SUBSCRIPTION_BASE_URL, subscription.baseUrl)
putExtra(MainActivity.EXTRA_SUBSCRIPTION_TOPIC, subscription.topic) 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_INSTANT, subscription.instant)
putExtra(MainActivity.EXTRA_SUBSCRIPTION_MUTED_UNTIL, subscription.mutedUntil) putExtra(MainActivity.EXTRA_SUBSCRIPTION_MUTED_UNTIL, subscription.mutedUntil)
} }

View file

@ -54,6 +54,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
private var subscriptionId: Long = 0L // Set in onCreate() private var subscriptionId: Long = 0L // Set in onCreate()
private var subscriptionBaseUrl: String = "" // Set in onCreate() private var subscriptionBaseUrl: String = "" // Set in onCreate()
private var subscriptionTopic: 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 subscriptionInstant: Boolean = false // Set in onCreate() & updated by options menu!
private var subscriptionMutedUntil: Long = 0L // Set in onCreate() & updated by options menu! private var subscriptionMutedUntil: Long = 0L // Set in onCreate() & updated by options menu!
@ -97,7 +98,6 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
val secure = url.getBooleanQueryParameter("secure", true) val secure = url.getBooleanQueryParameter("secure", true)
val baseUrl = if (secure) "https://${url.host}" else "http://${url.host}" val baseUrl = if (secure) "https://${url.host}" else "http://${url.host}"
val topic = url.pathSegments.first() val topic = url.pathSegments.first()
title = topicShortUrl(baseUrl, topic)
// Subscribe to topic if it doesn't already exist // Subscribe to topic if it doesn't already exist
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
@ -116,6 +116,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
icon = null, icon = null,
upAppId = null, upAppId = null,
upConnectorToken = null, upConnectorToken = null,
displayName = null,
totalCount = 0, totalCount = 0,
newCount = 0, newCount = 0,
lastActive = Date().time/1000 lastActive = Date().time/1000
@ -143,10 +144,13 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
} }
} }
title = displayName(subscription)
// Add extras needed in loadView(); normally these are added in MainActivity // Add extras needed in loadView(); normally these are added in MainActivity
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_ID, subscription.id) intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_ID, subscription.id)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_BASE_URL, subscription.baseUrl) intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_BASE_URL, subscription.baseUrl)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_TOPIC, subscription.topic) 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_INSTANT, subscription.instant)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_MUTED_UNTIL, subscription.mutedUntil) intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_MUTED_UNTIL, subscription.mutedUntil)
@ -161,13 +165,14 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
subscriptionId = intent.getLongExtra(MainActivity.EXTRA_SUBSCRIPTION_ID, 0) subscriptionId = intent.getLongExtra(MainActivity.EXTRA_SUBSCRIPTION_ID, 0)
subscriptionBaseUrl = intent.getStringExtra(MainActivity.EXTRA_SUBSCRIPTION_BASE_URL) ?: return subscriptionBaseUrl = intent.getStringExtra(MainActivity.EXTRA_SUBSCRIPTION_BASE_URL) ?: return
subscriptionTopic = intent.getStringExtra(MainActivity.EXTRA_SUBSCRIPTION_TOPIC) ?: 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) subscriptionInstant = intent.getBooleanExtra(MainActivity.EXTRA_SUBSCRIPTION_INSTANT, false)
subscriptionMutedUntil = intent.getLongExtra(MainActivity.EXTRA_SUBSCRIPTION_MUTED_UNTIL, 0L) subscriptionMutedUntil = intent.getLongExtra(MainActivity.EXTRA_SUBSCRIPTION_MUTED_UNTIL, 0L)
// Set title // Set title
val subscriptionBaseUrl = intent.getStringExtra(MainActivity.EXTRA_SUBSCRIPTION_BASE_URL) ?: return val subscriptionBaseUrl = intent.getStringExtra(MainActivity.EXTRA_SUBSCRIPTION_BASE_URL) ?: return
val topicUrl = topicShortUrl(subscriptionBaseUrl, subscriptionTopic) val topicUrl = topicShortUrl(subscriptionBaseUrl, subscriptionTopic)
title = topicUrl title = subscriptionDisplayName
// Set "how to instructions" // Set "how to instructions"
val howToExample: TextView = findViewById(R.id.detail_how_to_example) val howToExample: TextView = findViewById(R.id.detail_how_to_example)
@ -263,9 +268,11 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
val subscription = repository.getSubscription(subscriptionId) ?: return@launch val subscription = repository.getSubscription(subscriptionId) ?: return@launch
subscriptionInstant = subscription.instant subscriptionInstant = subscription.instant
subscriptionMutedUntil = subscription.mutedUntil subscriptionMutedUntil = subscription.mutedUntil
subscriptionDisplayName = displayName(subscription)
showHideInstantMenuItems(subscriptionInstant) showHideInstantMenuItems(subscriptionInstant)
showHideMutedUntilMenuItems(subscriptionMutedUntil) showHideMutedUntilMenuItems(subscriptionMutedUntil)
updateTitle(subscriptionDisplayName)
} }
} }
@ -543,6 +550,12 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
} }
} }
private fun updateTitle(subscriptionDisplayName: String) {
runOnUiThread {
title = subscriptionDisplayName
}
}
private fun onClearClick() { private fun onClearClick() {
Log.d(TAG, "Clearing all notifications for ${topicShortUrl(subscriptionBaseUrl, subscriptionTopic)}") Log.d(TAG, "Clearing all notifications for ${topicShortUrl(subscriptionBaseUrl, subscriptionTopic)}")
@ -571,6 +584,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
intent.putExtra(EXTRA_SUBSCRIPTION_ID, subscriptionId) intent.putExtra(EXTRA_SUBSCRIPTION_ID, subscriptionId)
intent.putExtra(EXTRA_SUBSCRIPTION_BASE_URL, subscriptionBaseUrl) intent.putExtra(EXTRA_SUBSCRIPTION_BASE_URL, subscriptionBaseUrl)
intent.putExtra(EXTRA_SUBSCRIPTION_TOPIC, subscriptionTopic) intent.putExtra(EXTRA_SUBSCRIPTION_TOPIC, subscriptionTopic)
intent.putExtra(EXTRA_SUBSCRIPTION_DISPLAY_NAME, subscriptionDisplayName)
startActivity(intent) startActivity(intent)
} }
@ -747,5 +761,6 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
const val EXTRA_SUBSCRIPTION_ID = "subscriptionId" const val EXTRA_SUBSCRIPTION_ID = "subscriptionId"
const val EXTRA_SUBSCRIPTION_BASE_URL = "baseUrl" const val EXTRA_SUBSCRIPTION_BASE_URL = "baseUrl"
const val EXTRA_SUBSCRIPTION_TOPIC = "topic" const val EXTRA_SUBSCRIPTION_TOPIC = "topic"
const val EXTRA_SUBSCRIPTION_DISPLAY_NAME = "displayName"
} }
} }

View file

@ -55,9 +55,8 @@ class DetailSettingsActivity : AppCompatActivity() {
} }
// Title // Title
val baseUrl = intent.getStringExtra(DetailActivity.EXTRA_SUBSCRIPTION_BASE_URL) ?: return val displayName = intent.getStringExtra(DetailActivity.EXTRA_SUBSCRIPTION_DISPLAY_NAME) ?: return
val topic = intent.getStringExtra(DetailActivity.EXTRA_SUBSCRIPTION_TOPIC) ?: return title = displayName
title = topicShortUrl(baseUrl, topic)
// Show 'Back' button // Show 'Back' button
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
@ -108,6 +107,7 @@ class DetailSettingsActivity : AppCompatActivity() {
loadAutoDeletePref() loadAutoDeletePref()
loadIconSetPref() loadIconSetPref()
loadIconRemovePref() loadIconRemovePref()
loadDisplayNamePref()
} }
private fun loadInstantPref() { private fun loadInstantPref() {
@ -276,6 +276,33 @@ class DetailSettingsActivity : AppCompatActivity() {
} }
} }
private fun loadDisplayNamePref() {
val prefId = context?.getString(R.string.detail_settings_appearance_display_name_key) ?: return
val pref: EditTextPreference? = findPreference(prefId)
pref?.isVisible = true // Hack: Show all settings at once, because subscription is loaded asynchronously
pref?.text = subscription.displayName
pref?.preferenceDataStore = object : PreferenceDataStore() {
override fun putString(key: String?, value: String?) {
val displayName: String? = if (value == "") {
null
} else {
value
}
val newSubscription = subscription.copy(displayName = displayName)
save(newSubscription) // TODO: does this need refresh=true?
activity?.runOnUiThread {
activity?.title = displayName(newSubscription)
}
}
override fun getString(key: String?, defValue: String?): String {
return subscription.displayName ?: ""
}
}
pref?.summaryProvider = Preference.SummaryProvider<EditTextPreference> { _ ->
getString(R.string.detail_settings_appearance_display_name_summary, displayName(subscription), topicShortUrl(subscription.baseUrl, subscription.topic))
}
}
private fun createIconPickLauncher(): ActivityResultLauncher<String> { private fun createIconPickLauncher(): ActivityResultLauncher<String> {
return registerForActivityResult(ActivityResultContracts.GetContent()) { inputUri -> return registerForActivityResult(ActivityResultContracts.GetContent()) { inputUri ->
if (inputUri == null) { if (inputUri == null) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -38,5 +38,10 @@
app:title="@string/detail_settings_appearance_icon_remove_title" app:title="@string/detail_settings_appearance_icon_remove_title"
app:summary="@string/detail_settings_appearance_icon_remove_summary" app:summary="@string/detail_settings_appearance_icon_remove_summary"
app:isPreferenceVisible="false"/> app:isPreferenceVisible="false"/>
<EditTextPreference
app:key="@string/detail_settings_appearance_display_name_key"
app:title="@string/detail_settings_appearance_display_name_title"
app:summary="@string/detail_settings_appearance_display_name_summary"
app:isPreferenceVisible="false"/>
</PreferenceCategory> </PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>