This commit is contained in:
Philipp Heckel 2022-05-08 20:41:17 -04:00
parent a498d68bcf
commit 18261263dd
4 changed files with 51 additions and 29 deletions

View file

@ -1,8 +1,10 @@
package io.heckel.ntfy.ui
import android.content.ContentResolver
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Bundle
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
@ -67,6 +69,7 @@ class DetailSettingsActivity : AppCompatActivity() {
}
class SettingsFragment : PreferenceFragmentCompat() {
private lateinit var resolver: ContentResolver
private lateinit var repository: Repository
private lateinit var serviceManager: SubscriberServiceManager
private lateinit var subscription: Subscription
@ -81,6 +84,7 @@ class DetailSettingsActivity : AppCompatActivity() {
// Dependencies (Fragments need a default constructor)
repository = Repository.getInstance(requireActivity())
serviceManager = SubscriberServiceManager(requireActivity())
resolver = requireContext().applicationContext.contentResolver
// Create result launcher for custom icon (must be created in onCreatePreferences() directly)
iconSetLauncher = createIconPickLauncher()
@ -251,28 +255,26 @@ class DetailSettingsActivity : AppCompatActivity() {
private fun loadIconRemovePref() {
val prefId = context?.getString(R.string.detail_settings_appearance_icon_remove_key) ?: return
iconRemovePref = findPreference(prefId) ?: return
iconRemovePref.isVisible = subscription.icon != null
iconRemovePref.preferenceDataStore = object : PreferenceDataStore() { } // Dummy store to protect from accidentally overwriting
iconRemovePref.onPreferenceClickListener = Preference.OnPreferenceClickListener { _ ->
iconRemovePref.isVisible = false
iconSetPref.isVisible = true
deleteIcon(subscription.icon)
save(subscription.copy(icon = null))
true
}
// FIXME
// Set icon (if it exists)
if (subscription.icon != null) {
try {
val resolver = requireContext().applicationContext.contentResolver
val bitmapStream = resolver.openInputStream(Uri.parse(subscription.icon))
val bitmap = BitmapFactory.decodeStream(bitmapStream)
iconRemovePref.icon = bitmap.toDrawable(resources)
} catch (e: Exception) {
// FIXME
Log.w(TAG, "Unable to set icon ${subscription.icon}", e)
}
}
iconRemovePref.isVisible = subscription.icon != null
iconRemovePref.preferenceDataStore = object : PreferenceDataStore() { } // Dummy store to protect from accidentally overwriting
iconRemovePref.onPreferenceClickListener = Preference.OnPreferenceClickListener { _ ->
save(subscription.copy(icon = null))
iconRemovePref.isVisible = false
iconSetPref.isVisible = true
true
}
}
private fun createIconPickLauncher(): ActivityResultLauncher<String> {
@ -281,45 +283,54 @@ class DetailSettingsActivity : AppCompatActivity() {
return@registerForActivityResult
}
lifecycleScope.launch(Dispatchers.IO) {
val outputUri = createUri() ?: return@launch
try {
// Write to cache storage
val resolver = requireContext().applicationContext.contentResolver
val inputStream = resolver.openInputStream(inputUri) ?: throw IOException("Couldn't open content URI for reading")
val outputUri = createUri()
val outputStream = resolver.openOutputStream(outputUri) ?: throw IOException("Couldn't open content URI for writing")
inputStream.copyTo(outputStream)
save(subscription.copy(icon = outputUri.toString()))
// FIXME
// FIXME
iconSetPref.isVisible = false
inputStream.use {
it.copyTo(outputStream)
}
// Read image and set as preference icon
val bitmapStream = resolver.openInputStream(Uri.parse(outputUri.toString()))
val bitmap = BitmapFactory.decodeStream(bitmapStream)
// Display "remove" preference
iconRemovePref.icon = bitmap.toDrawable(resources)
iconRemovePref.isVisible = true
iconSetPref.isVisible = false
// Finally, save (this is last!)
save(subscription.copy(icon = outputUri.toString()))
} catch (e: Exception) {
Log.w(TAG, "Saving icon failed", e)
requireActivity().runOnUiThread {
// FIXME TOAST
Toast.makeText(context, getString(R.string.detail_settings_appearance_icon_error_saving, e.message), Toast.LENGTH_LONG).show()
}
}
}
}
}
private fun createUri(): Uri {
private fun createUri(): Uri? {
val dir = File(requireContext().cacheDir, SUBSCRIPTION_ICONS)
if (!dir.exists() && !dir.mkdirs()) {
throw Exception("Cannot create cache directory for attachments: $dir")
return null
}
val file = File(dir, subscription.id.toString())
return FileProvider.getUriForFile(requireContext(), DownloadWorker.FILE_PROVIDER_AUTHORITY, file)
}
private fun loadBitmap() {
// FIXME
private fun deleteIcon(uri: String?) {
if (uri == null) {
return
}
try {
resolver.delete(Uri.parse(uri), null, null)
} catch (e: Exception) {
Log.w(TAG, "Unable to delete $uri", e)
}
}
private fun save(newSubscription: Subscription, refresh: Boolean = false) {

View file

@ -1,12 +1,14 @@
package io.heckel.ntfy.ui
import android.content.Context
import android.net.Uri
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import io.heckel.ntfy.db.*
import io.heckel.ntfy.up.Distributor
import io.heckel.ntfy.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlin.collections.List
@ -32,6 +34,14 @@ class SubscriptionsViewModel(private val repository: Repository) : ViewModel() {
}
repository.removeAllNotifications(subscriptionId)
repository.removeSubscription(subscriptionId)
if (subscription.icon != null) {
val resolver = context.applicationContext.contentResolver
try {
resolver.delete(Uri.parse(subscription.icon), null, null)
} catch (_: Exception) {
// Don't care
}
}
}
suspend fun get(baseUrl: String, topic: String): Subscription? {

View file

@ -12,7 +12,7 @@
android:layout_height="35dp" app:srcCompat="@drawable/ic_sms_gray_24dp"
android:id="@+id/main_item_image" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginTop="13dp"/>
android:layout_marginTop="17dp" android:scaleType="fitStart"/>
<TextView
android:text="ntfy.sh/example"
android:layout_width="0dp"

View file

@ -341,8 +341,9 @@
<string name="detail_settings_notifications_instant_summary_off">Notifications are delivered using Firebase. Delivery may be delayed, but consumes less battery.</string>
<string name="detail_settings_appearance_header">Appearance</string>
<string name="detail_settings_appearance_icon_title">Subscription icon</string>
<string name="detail_settings_appearance_icon_set_summary_set">This icon is displayed in notifications. Tap to remove it.</string>
<string name="detail_settings_appearance_icon_set_summary_set">This icon is displayed in notifications to this topic. Tap to remove it.</string>
<string name="detail_settings_appearance_icon_set_summary_no_set">Set an icon to be displayed in notifications</string>
<string name="detail_settings_appearance_icon_error_saving">Unable to save icon: %1$s</string>
<string name="detail_settings_global_setting_title">Use global setting</string>
<string name="detail_settings_global_setting_suffix">global</string>