Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
447 changes: 447 additions & 0 deletions app/schemas/io.heckel.ntfy.db.Database/19.json

Large diffs are not rendered by default.

13 changes: 11 additions & 2 deletions app/src/main/java/io/heckel/ntfy/backup/Backuper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ class Backuper(val context: Context) {
upAppId = s.upAppId,
upConnectorToken = s.upConnectorToken,
displayName = s.displayName,
layout = s.layout ?: Repository.LAYOUT_DEFAULT,
linkHandler = s.linkHandler ?: Repository.LINK_HANDLER_DEFAULT,
notificationButtons = s.notificationButtons ?: Repository.NOTIFICATION_BUTTONS_DEFAULT
)
repository.addSubscription(subscription)

Expand Down Expand Up @@ -298,7 +301,10 @@ class Backuper(val context: Context) {
icon = s.icon,
upAppId = s.upAppId,
upConnectorToken = s.upConnectorToken,
displayName = s.displayName
displayName = s.displayName,
layout = s.layout,
linkHandler = s.linkHandler,
notificationButtons = s.notificationButtons
)
}
}
Expand Down Expand Up @@ -438,7 +444,10 @@ data class Subscription(
val icon: String?,
val upAppId: String?,
val upConnectorToken: String?,
val displayName: String?
val displayName: String?,
val layout: Int?,
val linkHandler: String?,
val notificationButtons: String?,
)

data class Notification(
Expand Down
36 changes: 29 additions & 7 deletions app/src/main/java/io/heckel/ntfy/db/Database.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ data class Subscription(
@ColumnInfo(name = "upConnectorToken") val upConnectorToken: String?, // UnifiedPush connector token
@ColumnInfo(name = "displayName") val displayName: String?,
@ColumnInfo(name = "dedicatedChannels") val dedicatedChannels: Boolean,
@ColumnInfo(name = "layout") val layout: Int,
@ColumnInfo(name = "linkHandler") val linkHandler: String,
@ColumnInfo(name = "notificationButtons") val notificationButtons: String,
@Ignore val totalCount: Int = 0, // Total notifications
@Ignore val newCount: Int = 0, // New notifications
@Ignore val lastActive: Long = 0, // Unix timestamp
Expand All @@ -63,7 +66,10 @@ data class Subscription(
upAppId: String,
upConnectorToken: String,
displayName: String?,
dedicatedChannels: Boolean
dedicatedChannels: Boolean,
layout: Int,
linkHandler: String,
notificationButtons: String,
) :
this(
id,
Expand All @@ -80,6 +86,9 @@ data class Subscription(
upConnectorToken,
displayName,
dedicatedChannels,
layout,
linkHandler,
notificationButtons,
totalCount = 0,
newCount = 0,
lastActive = 0,
Expand Down Expand Up @@ -136,6 +145,9 @@ data class SubscriptionWithMetadata(
val upConnectorToken: String?,
val displayName: String?,
val dedicatedChannels: Boolean,
val layout: Int,
val linkHandler: String,
val notificationButtons: String,
val totalCount: Int,
val newCount: Int,
val lastActive: Long
Expand Down Expand Up @@ -298,7 +310,7 @@ data class LogEntry(
}

@androidx.room.Database(
version = 18,
version = 19,
entities = [
Subscription::class,
Notification::class,
Expand Down Expand Up @@ -344,6 +356,7 @@ abstract class Database : RoomDatabase() {
.addMigrations(MIGRATION_15_16)
.addMigrations(MIGRATION_16_17)
.addMigrations(MIGRATION_17_18)
.addMigrations(MIGRATION_18_19)
.fallbackToDestructiveMigration(true)
.build()
this.instance = instance
Expand Down Expand Up @@ -484,14 +497,23 @@ abstract class Database : RoomDatabase() {
db.execSQL("UPDATE Notification SET sequenceId = id WHERE sequenceId = ''")
}
}

private val MIGRATION_18_19 = object : Migration(18, 19) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Subscription ADD COLUMN layout INT NOT NULL DEFAULT (0)")
db.execSQL("ALTER TABLE Subscription ADD COLUMN linkHandler TEXT NOT NULL DEFAULT 'web'")
db.execSQL("ALTER TABLE Subscription ADD COLUMN notificationButtons TEXT NOT NULL DEFAULT 'open|browse'")
}
}

}
}

@Dao
interface SubscriptionDao {
@Query("""
SELECT
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.insistent, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken, s.displayName, s.dedicatedChannels,
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.insistent, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken, s.displayName, s.dedicatedChannels, s.layout, s.linkHandler, s.notificationButtons,
COUNT(n.id) totalCount,
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
IFNULL(MAX(n.timestamp),0) AS lastActive
Expand All @@ -504,7 +526,7 @@ interface SubscriptionDao {

@Query("""
SELECT
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.insistent, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken, s.displayName, s.dedicatedChannels,
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.insistent, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken, s.displayName, s.dedicatedChannels, s.layout, s.linkHandler, s.notificationButtons,
COUNT(n.id) totalCount,
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
IFNULL(MAX(n.timestamp),0) AS lastActive
Expand All @@ -517,7 +539,7 @@ interface SubscriptionDao {

@Query("""
SELECT
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.insistent, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken, s.displayName, s.dedicatedChannels,
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.insistent, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken, s.displayName, s.dedicatedChannels, s.layout, s.linkHandler, s.notificationButtons,
COUNT(n.id) totalCount,
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
IFNULL(MAX(n.timestamp),0) AS lastActive
Expand All @@ -530,7 +552,7 @@ interface SubscriptionDao {

@Query("""
SELECT
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.insistent, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken, s.displayName, s.dedicatedChannels,
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.insistent, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken, s.displayName, s.dedicatedChannels, s.layout, s.linkHandler, s.notificationButtons,
COUNT(n.id) totalCount,
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
IFNULL(MAX(n.timestamp),0) AS lastActive
Expand All @@ -543,7 +565,7 @@ interface SubscriptionDao {

@Query("""
SELECT
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.insistent, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken, s.displayName, s.dedicatedChannels,
s.id, s.baseUrl, s.topic, s.instant, s.mutedUntil, s.minPriority, s.autoDelete, s.insistent, s.lastNotificationId, s.icon, s.upAppId, s.upConnectorToken, s.displayName, s.dedicatedChannels, s.layout, s.linkHandler, s.notificationButtons,
COUNT(n.id) totalCount,
COUNT(CASE n.notificationId WHEN 0 THEN NULL ELSE n.id END) newCount,
IFNULL(MAX(n.timestamp),0) AS lastActive
Expand Down
16 changes: 14 additions & 2 deletions app/src/main/java/io/heckel/ntfy/db/Repository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,10 @@ class Repository(private val sharedPrefs: SharedPreferences, database: Database)
totalCount = s.totalCount,
newCount = s.newCount,
lastActive = s.lastActive,
connectionDetails = connectionDetails[s.baseUrl] ?: ConnectionDetails()
connectionDetails = connectionDetails[s.baseUrl] ?: ConnectionDetails(),
layout = s.layout,
linkHandler = s.linkHandler,
notificationButtons = s.notificationButtons
)
}
}
Expand All @@ -566,7 +569,10 @@ class Repository(private val sharedPrefs: SharedPreferences, database: Database)
totalCount = s.totalCount,
newCount = s.newCount,
lastActive = s.lastActive,
connectionDetails = connectionDetails[s.baseUrl] ?: ConnectionDetails()
connectionDetails = connectionDetails[s.baseUrl] ?: ConnectionDetails(),
layout = s.layout,
linkHandler = s.linkHandler,
notificationButtons = s.notificationButtons
)
}

Expand Down Expand Up @@ -664,6 +670,12 @@ class Repository(private val sharedPrefs: SharedPreferences, database: Database)
const val WEBSOCKET_RECONNECT_REMIND_TIME_ALWAYS = 1L
const val WEBSOCKET_RECONNECT_REMIND_TIME_NEVER = Long.MAX_VALUE

const val LAYOUT_DEFAULT = 0

const val LINK_HANDLER_DEFAULT = "web"

const val NOTIFICATION_BUTTONS_DEFAULT = "open|browse"

private const val TAG = "NtfyRepository"
private var instance: Repository? = null

Expand Down
10 changes: 8 additions & 2 deletions app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,14 @@ class NotificationService(val context: Context) {
maybeSetDeleteIntent(builder, insistent)
maybeSetSound(builder, insistent, update)
maybeSetProgress(builder, notification)
maybeAddOpenAction(builder, notification)
maybeAddBrowseAction(builder, notification)

if(subscription.notificationButtons.contains("open")){
maybeAddOpenAction(builder, notification)
}
if(subscription.notificationButtons.contains("browse")){
maybeAddBrowseAction(builder, notification)
}

maybeAddDownloadAction(builder, notification)
maybeAddCancelAction(builder, notification)
maybeAddUserActions(builder, notification)
Expand Down
20 changes: 19 additions & 1 deletion app/src/main/java/io/heckel/ntfy/ui/DetailActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ class DetailActivity : AppCompatActivity(), NotificationFragment.NotificationSet
private var subscriptionTopic: String = "" // Set in onCreate()
private var subscriptionDisplayName: String = "" // Set in onCreate() & updated by options menu!
private var subscriptionMutedUntil: Long = 0L // Set in onCreate() & updated by options menu!
private var subscriptionLayout: Int = Repository.LAYOUT_DEFAULT
private var subscriptionLinkHandler: String = Repository.LINK_HANDLER_DEFAULT

// UI elements
private lateinit var adapter: DetailAdapter
Expand Down Expand Up @@ -234,7 +236,10 @@ class DetailActivity : AppCompatActivity(), NotificationFragment.NotificationSet
displayName = displayName,
totalCount = 0,
newCount = 0,
lastActive = Date().time/1000
lastActive = Date().time/1000,
layout = Repository.LAYOUT_DEFAULT,
linkHandler = Repository.LINK_HANDLER_DEFAULT,
notificationButtons = Repository.NOTIFICATION_BUTTONS_DEFAULT
)
repository.addSubscription(subscription)

Expand Down Expand Up @@ -264,6 +269,8 @@ class DetailActivity : AppCompatActivity(), NotificationFragment.NotificationSet
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_DISPLAY_NAME, displayName(appBaseUrl, subscription))
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_INSTANT, subscription.instant)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_MUTED_UNTIL, subscription.mutedUntil)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_LAYOUT, subscription.layout)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_LINK_HANDLER, subscription.linkHandler)

runOnUiThread {
loadView()
Expand All @@ -285,6 +292,8 @@ class DetailActivity : AppCompatActivity(), NotificationFragment.NotificationSet
subscriptionTopic = intent.getStringExtra(MainActivity.EXTRA_SUBSCRIPTION_TOPIC) ?: return
subscriptionDisplayName = intent.getStringExtra(MainActivity.EXTRA_SUBSCRIPTION_DISPLAY_NAME) ?: return
subscriptionMutedUntil = intent.getLongExtra(MainActivity.EXTRA_SUBSCRIPTION_MUTED_UNTIL, 0L)
subscriptionLayout = intent.getIntExtra(MainActivity.EXTRA_SUBSCRIPTION_LAYOUT, Repository.LAYOUT_DEFAULT)
subscriptionLinkHandler = intent.getStringExtra(MainActivity.EXTRA_SUBSCRIPTION_LINK_HANDLER) ?: return

// Set title
val subscriptionBaseUrl = intent.getStringExtra(MainActivity.EXTRA_SUBSCRIPTION_BASE_URL) ?: return
Expand Down Expand Up @@ -540,6 +549,15 @@ class DetailActivity : AppCompatActivity(), NotificationFragment.NotificationSet

showHideMenuItems()
updateTitle(subscriptionDisplayName)

if(subscriptionLayout != subscription.layout || subscriptionLinkHandler != subscription.linkHandler){
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_LAYOUT, subscription.layout)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_LINK_HANDLER, subscription.linkHandler)

runOnUiThread {
loadView()
}
}
}
}

Expand Down
22 changes: 19 additions & 3 deletions app/src/main/java/io/heckel/ntfy/ui/DetailAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,15 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope:

/* Creates and inflates view and return TopicViewHolder. */
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DetailViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.fragment_detail_item, parent, false)
val layout = activity.intent.getIntExtra(MainActivity.EXTRA_SUBSCRIPTION_LAYOUT, 0)

val layoutMap = mapOf(
1 to R.layout.fragment_detail_item_layout_1,
)

val layoutId = layoutMap[layout] ?: R.layout.fragment_detail_item

val view = LayoutInflater.from(parent.context).inflate(layoutId, parent, false)
return DetailViewHolder(activity, lifecycleScope, repository, markwon, view, selected, onClick, onLongClick)
}

Expand Down Expand Up @@ -120,7 +127,16 @@ class DetailAdapter(private val activity: Activity, private val lifecycleScope:
messageView.autoLinkMask = 0
markwon.setMarkdown(messageView, message.toString())
} else {
messageView.autoLinkMask = Linkify.WEB_URLS or Linkify.EMAIL_ADDRESSES or Linkify.PHONE_NUMBERS
val linkHandler = activity.intent.getStringExtra(MainActivity.EXTRA_SUBSCRIPTION_LINK_HANDLER)

val autoLinkMask = listOf(
Linkify.WEB_URLS to "web",
Linkify.EMAIL_ADDRESSES to "email",
Linkify.PHONE_NUMBERS to "phone"
).filter { linkHandler?.contains(it.second) == true }
.fold(0) { acc, pair -> acc or pair.first }

messageView.autoLinkMask = autoLinkMask
messageView.text = message
}
messageView.movementMethod = BetterLinkMovementMethod.getInstance()
Expand Down
Loading