Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Notifications settings #13

Merged
merged 1 commit into from
Oct 25, 2024
Merged
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
75 changes: 74 additions & 1 deletion app/src/main/java/com/koalasat/pokey/models/EncryptedStorage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,22 @@ import androidx.security.crypto.MasterKey

object PrefKeys {
const val NOSTR_PUBKEY = "nostr_pubkey"
const val NOTIFY_REPLIES = "notify_replies"
const val NOTIFY_PRIVATE = "notify_private"
const val NOTIFY_ZAPS = "notify_zaps"
const val NOTIFY_QUOTES = "notify_quotes"
const val NOTIFY_REACTIONS = "notify_reactions"
const val NOTIFY_MENTIONS = "notify_mentions"
const val NOTIFY_REPOSTS = "notify_reposts"
}
object DefaultKeys {
const val NOTIFY_REPLIES = true
const val NOTIFY_REACTIONS = true
const val NOTIFY_PRIVATE = true
const val NOTIFY_ZAPS = true
const val NOTIFY_QUOTES = true
const val NOTIFY_MENTIONS = true
const val NOTIFY_REPOSTS = true
}

object EncryptedStorage {
Expand All @@ -19,6 +35,21 @@ object EncryptedStorage {
private val _pubKey = MutableLiveData<String>()
val pubKey: LiveData<String> get() = _pubKey

private val _notifyReplies = MutableLiveData<Boolean>().apply { DefaultKeys.NOTIFY_REPLIES }
val notifyReplies: LiveData<Boolean> get() = _notifyReplies
private val _notifyReactions = MutableLiveData<Boolean>().apply { DefaultKeys.NOTIFY_REACTIONS }
val notifyReactions: LiveData<Boolean> get() = _notifyReactions
private val _notifyPrivate = MutableLiveData<Boolean>().apply { DefaultKeys.NOTIFY_PRIVATE }
val notifyPrivate: LiveData<Boolean> get() = _notifyPrivate
private val _notifyZaps = MutableLiveData<Boolean>().apply { DefaultKeys.NOTIFY_ZAPS }
val notifyZaps: LiveData<Boolean> get() = _notifyZaps
private val _notifyQuotes = MutableLiveData<Boolean>().apply { DefaultKeys.NOTIFY_QUOTES }
val notifyQuotes: LiveData<Boolean> get() = _notifyQuotes
private val _notifyMentions = MutableLiveData<Boolean>().apply { DefaultKeys.NOTIFY_MENTIONS }
val notifyMentions: LiveData<Boolean> get() = _notifyMentions
private val _notifyResposts = MutableLiveData<Boolean>().apply { DefaultKeys.NOTIFY_REPOSTS }
val notifyResposts: LiveData<Boolean> get() = _notifyResposts

fun init(context: Context) {
val masterKey: MasterKey =
MasterKey.Builder(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS)
Expand All @@ -33,11 +64,53 @@ object EncryptedStorage {
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM,
) as EncryptedSharedPreferences

_pubKey.value = sharedPreferences.getString(PrefKeys.NOSTR_PUBKEY, "").toString()
_pubKey.value = sharedPreferences.getString(PrefKeys.NOSTR_PUBKEY, "")
_notifyReplies.value = sharedPreferences.getBoolean(PrefKeys.NOTIFY_REPLIES, DefaultKeys.NOTIFY_REPLIES)
_notifyReactions.value = sharedPreferences.getBoolean(PrefKeys.NOTIFY_REACTIONS, DefaultKeys.NOTIFY_REACTIONS)
_notifyPrivate.value = sharedPreferences.getBoolean(PrefKeys.NOTIFY_PRIVATE, DefaultKeys.NOTIFY_PRIVATE)
_notifyZaps.value = sharedPreferences.getBoolean(PrefKeys.NOTIFY_ZAPS, DefaultKeys.NOTIFY_ZAPS)
_notifyQuotes.value = sharedPreferences.getBoolean(PrefKeys.NOTIFY_QUOTES, DefaultKeys.NOTIFY_QUOTES)
_notifyMentions.value = sharedPreferences.getBoolean(PrefKeys.NOTIFY_MENTIONS, DefaultKeys.NOTIFY_MENTIONS)
_notifyResposts.value = sharedPreferences.getBoolean(PrefKeys.NOTIFY_REPOSTS, DefaultKeys.NOTIFY_REPOSTS)
}

fun updatePubKey(newValue: String) {
sharedPreferences.edit().putString(PrefKeys.NOSTR_PUBKEY, newValue).apply()
_pubKey.value = newValue
}

fun updateNotifyReplies(newValue: Boolean) {
sharedPreferences.edit().putBoolean(PrefKeys.NOTIFY_REPLIES, newValue).apply()
_notifyReplies.value = newValue
}

fun updateNotifyReactions(newValue: Boolean) {
sharedPreferences.edit().putBoolean(PrefKeys.NOTIFY_REACTIONS, newValue).apply()
_notifyReactions.value = newValue
}

fun updateNotifyPrivate(newValue: Boolean) {
sharedPreferences.edit().putBoolean(PrefKeys.NOTIFY_PRIVATE, newValue).apply()
_notifyPrivate.value = newValue
}

fun updateNotifyZaps(newValue: Boolean) {
sharedPreferences.edit().putBoolean(PrefKeys.NOTIFY_ZAPS, newValue).apply()
_notifyZaps.value = newValue
}

fun updateNotifyQuotes(newValue: Boolean) {
sharedPreferences.edit().putBoolean(PrefKeys.NOTIFY_QUOTES, newValue).apply()
_notifyQuotes.value = newValue
}

fun updateNotifyMentions(newValue: Boolean) {
sharedPreferences.edit().putBoolean(PrefKeys.NOTIFY_MENTIONS, newValue).apply()
_notifyMentions.value = newValue
}

fun updateNotifyReposts(newValue: Boolean) {
sharedPreferences.edit().putBoolean(PrefKeys.NOTIFY_REPOSTS, newValue).apply()
_notifyResposts.value = newValue
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import com.vitorpamplona.ammolite.relays.TypedFilter
import com.vitorpamplona.ammolite.relays.filters.EOSETime
import com.vitorpamplona.ammolite.relays.filters.SincePerRelayFilter
import com.vitorpamplona.quartz.encoders.Hex
import com.vitorpamplona.quartz.encoders.LnInvoiceUtil
import com.vitorpamplona.quartz.encoders.Nip19Bech32
import com.vitorpamplona.quartz.encoders.Nip19Bech32.uriToRoute
import com.vitorpamplona.quartz.encoders.toNote
Expand Down Expand Up @@ -334,37 +335,61 @@ class NotificationsService : Service() {
val pubKey = EncryptedStorage.pubKey
var nip32Bech32 = ""

if (event.kind == 1) {
title = if (event.content().contains("nostr:$pubKey")) {
getString(R.string.new_mention)
} else if (event.content().contains("nostr:nevent1")) {
getString(R.string.new_quote)
} else {
getString(R.string.new_reply)
when (event.kind) {
1 -> {
title = when {
event.content().contains("nostr:$pubKey") -> {
if (!EncryptedStorage.notifyMentions.value!!) return@launch
getString(R.string.new_mention)
}
event.content().contains("nostr:nevent1") -> {
if (!EncryptedStorage.notifyQuotes.value!!) return@launch
getString(R.string.new_quote)
}
else -> {
if (!EncryptedStorage.notifyReplies.value!!) return@launch
getString(R.string.new_reply)
}
}
text = event.content().replace(Regex("nostr:[a-zA-Z0-9]+"), "")
nip32Bech32 = Hex.decode(event.id).toNote()
}
6 -> {
if (!EncryptedStorage.notifyResposts.value!!) return@launch

title = getString(R.string.new_repost)
nip32Bech32 = Hex.decode(event.id).toNote()
}
text = event.content().replace(Regex("nostr:[a-zA-Z0-9]+"), "")
nip32Bech32 = Hex.decode(event.id).toNote()
} else if (event.kind == 6) {
title = getString(R.string.new_repost)
nip32Bech32 = Hex.decode(event.id).toNote()
} else if (event.kind == 4 || event.kind == 13) {
title = getString(R.string.new_private)
nip32Bech32 = Hex.decode(event.pubKey).toNpub()
} else if (event.kind == 7) {
title = getString(R.string.new_reaction)
text = if (event.content.isEmpty() || event.content == "+") {
"\uFE0F"
} else {
event.content
4, 13 -> {
if (!EncryptedStorage.notifyPrivate.value!!) return@launch

title = getString(R.string.new_private)
nip32Bech32 = Hex.decode(event.pubKey).toNpub()
}
7 -> {
if (!EncryptedStorage.notifyReactions.value!!) return@launch

title = getString(R.string.new_reaction)
text = if (event.content.isEmpty() || event.content == "+") {
"\uFE0F"
} else {
event.content
}
val taggedEvent = event.taggedEvents().first()
nip32Bech32 = Hex.decode(taggedEvent).toNote()
}
9735 -> {
if (!EncryptedStorage.notifyZaps.value!!) return@launch

title = getString(R.string.new_zap)
val bolt11 = event.firstTag("bolt11")
if (!bolt11.isNullOrEmpty()) {
val sats = LnInvoiceUtil.getAmountInSats(bolt11)
text = "$sats Sats"
}
}
val taggedEvent = event.taggedEvents().first()
nip32Bech32 = Hex.decode(taggedEvent).toNote()
} else if (event.kind == 9735) {
title = getString(R.string.new_zap)
var sats = event.zapraiserAmount()
text = "$sats Sats"
}
Log.d("Pokey", nip32Bech32)

if (title.isEmpty()) return@launch

displayNoteNotification(title, text, nip32Bech32, event)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,88 @@
package com.koalasat.pokey.ui.notifications

import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.koalasat.pokey.databinding.FragmentNotificationsBinding
import com.koalasat.pokey.models.EncryptedStorage

class NotificationsFragment : Fragment() {

private var _binding: FragmentNotificationsBinding? = null

// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
val notificationsViewModel =
val viewModel =
ViewModelProvider(this).get(NotificationsViewModel::class.java)

_binding = FragmentNotificationsBinding.inflate(inflater, container, false)
val root: View = binding.root

val textView: TextView = binding.textNotifications
notificationsViewModel.text.observe(viewLifecycleOwner) {
textView.text = it
viewModel.newReplies.value.apply { EncryptedStorage.notifyReplies.value }
binding.newReplies.setOnCheckedChangeListener { _, isChecked ->
viewModel.updateNotifyReplies(isChecked)
}
viewModel.newReplies.observe(viewLifecycleOwner) { value ->
binding.newReplies.isChecked = value
}

viewModel.newZaps.value.apply { EncryptedStorage.notifyZaps.value }
binding.newZaps.setOnCheckedChangeListener { _, isChecked ->
viewModel.updateNotifyZaps(isChecked)
}
viewModel.newZaps.observe(viewLifecycleOwner) { value ->
Log.d("Pokey", "binding.newZaps.isChecked" + binding.newZaps.isChecked)
binding.newZaps.isChecked = value
}

viewModel.newReactions.value.apply { EncryptedStorage.notifyReactions.value }
binding.newReactions.setOnCheckedChangeListener { _, isChecked ->
viewModel.updateNotifyReactions(isChecked)
}
viewModel.newReactions.observe(viewLifecycleOwner) { value ->
binding.newReactions.isChecked = value
}

viewModel.newPrivate.value.apply { EncryptedStorage.notifyPrivate.value }
binding.newPrivate.setOnCheckedChangeListener { _, isChecked ->
viewModel.updateNotifyPrivate(isChecked)
}
viewModel.newPrivate.observe(viewLifecycleOwner) { value ->
binding.newPrivate.isChecked = value
}

viewModel.newQuotes.value.apply { EncryptedStorage.notifyQuotes.value }
binding.newQuotes.setOnCheckedChangeListener { _, isChecked ->
viewModel.updateNotifyQuotes(isChecked)
}
viewModel.newQuotes.observe(viewLifecycleOwner) { value ->
binding.newQuotes.isChecked = value
}

viewModel.newMentions.value.apply { EncryptedStorage.notifyMentions.value }
binding.newMentions.setOnCheckedChangeListener { _, isChecked ->
viewModel.updateNotifyMentions(isChecked)
}
viewModel.newMentions.observe(viewLifecycleOwner) { value ->
binding.newMentions.isChecked = value
}

viewModel.newReposts.value.apply { EncryptedStorage.notifyResposts.value }
binding.newReposts.setOnCheckedChangeListener { _, isChecked ->
viewModel.updateNotifyReposts(isChecked)
}
viewModel.newReposts.observe(viewLifecycleOwner) { value ->
binding.newReposts.isChecked = value
}

return root
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,93 @@
package com.koalasat.pokey.ui.notifications

import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.koalasat.pokey.models.EncryptedStorage

class NotificationsViewModel : ViewModel() {

private val _text = MutableLiveData<String>().apply {
value = "Coming Soon!"
private val _newReplies = MutableLiveData<Boolean>().apply { value = EncryptedStorage.notifyReplies.value }
val newReplies: LiveData<Boolean> = _newReplies

private val _newZaps = MutableLiveData<Boolean>().apply { value = EncryptedStorage.notifyZaps.value }
val newZaps: LiveData<Boolean> = _newZaps

private val _newQuotes = MutableLiveData<Boolean>().apply { value = EncryptedStorage.notifyQuotes.value }
val newQuotes: LiveData<Boolean> = _newQuotes

private val _newReactions = MutableLiveData<Boolean>().apply { value = EncryptedStorage.notifyReactions.value }
val newReactions: LiveData<Boolean> = _newReactions

private val _newPrivate = MutableLiveData<Boolean>().apply { value = EncryptedStorage.notifyPrivate.value }
val newPrivate: LiveData<Boolean> = _newPrivate

private val _newMentions = MutableLiveData<Boolean>().apply { value = EncryptedStorage.notifyMentions.value }
val newMentions: LiveData<Boolean> = _newMentions

private val _newReposts = MutableLiveData<Boolean>().apply { value = EncryptedStorage.notifyResposts.value }
val newReposts: LiveData<Boolean> = _newReposts

init {
EncryptedStorage.notifyReplies.observeForever { value ->
_newReplies.value = value
}
Log.d("Pokey", "_newZaps.value" + _newZaps.value)
EncryptedStorage.notifyZaps.observeForever { value ->
_newZaps.value = value
Log.d("Pokey", "observeForever" + value)
}
EncryptedStorage.notifyQuotes.observeForever { value ->
_newQuotes.value = value
}
EncryptedStorage.notifyReactions.observeForever { value ->
_newReactions.value = value
}
EncryptedStorage.notifyPrivate.observeForever { value ->
_newPrivate.value = value
}
EncryptedStorage.notifyMentions.observeForever { value ->
_newMentions.value = value
}
EncryptedStorage.notifyResposts.observeForever { value ->
_newReposts.value = value
}
}

fun updateNotifyReplies(value: Boolean) {
_newReplies.value = value
EncryptedStorage.updateNotifyReplies(value)
}

fun updateNotifyReactions(value: Boolean) {
_newReactions.value = value
EncryptedStorage.updateNotifyReactions(value)
}

fun updateNotifyPrivate(value: Boolean) {
_newPrivate.value = value
EncryptedStorage.updateNotifyPrivate(value)
}

fun updateNotifyZaps(value: Boolean) {
_newZaps.value = value
Log.d("Pokey", "updateNotifyZaps" + value)
EncryptedStorage.updateNotifyZaps(value)
}

fun updateNotifyQuotes(value: Boolean) {
_newQuotes.value = value
EncryptedStorage.updateNotifyQuotes(value)
}

fun updateNotifyMentions(value: Boolean) {
_newMentions.value = value
EncryptedStorage.updateNotifyMentions(value)
}

fun updateNotifyReposts(value: Boolean) {
_newReposts.value = value
EncryptedStorage.updateNotifyReposts(value)
}
val text: LiveData<String> = _text
}
Loading
Loading