139 lines
6.0 KiB
Kotlin
139 lines
6.0 KiB
Kotlin
package se.ajpanton.notificationsmaster
|
|
|
|
import android.content.Intent
|
|
import android.media.RingtoneManager
|
|
import android.net.Uri
|
|
import android.os.Bundle
|
|
import android.view.View
|
|
import android.widget.Button
|
|
import android.widget.EditText
|
|
import android.widget.LinearLayout
|
|
import android.widget.Toast
|
|
import androidx.activity.result.contract.ActivityResultContracts
|
|
import androidx.fragment.app.Fragment
|
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|
import se.ajpanton.notificationsmaster.alerts.AlertConfigurationStore
|
|
import se.ajpanton.notificationsmaster.alerts.AlertProfile
|
|
import se.ajpanton.notificationsmaster.databinding.FragmentProfilesBinding
|
|
import java.util.UUID
|
|
|
|
class ProfilesFragment : Fragment(R.layout.fragment_profiles) {
|
|
private var binding: FragmentProfilesBinding? = null
|
|
private lateinit var store: AlertConfigurationStore
|
|
private var selectedSoundUri: String? = null
|
|
private var soundButton: Button? = null
|
|
private val chooseSound = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
|
selectedSoundUri = result.data?.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI, Uri::class.java)?.toString()
|
|
soundButton?.text = if (selectedSoundUri == null) "Choose sound" else "Change sound"
|
|
}
|
|
|
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
binding = FragmentProfilesBinding.bind(view)
|
|
store = AlertConfigurationStore(requireContext())
|
|
binding!!.addProfile.setOnClickListener { showEditor() }
|
|
refresh()
|
|
}
|
|
|
|
override fun onDestroyView() {
|
|
binding = null
|
|
soundButton = null
|
|
super.onDestroyView()
|
|
}
|
|
|
|
private fun refresh() {
|
|
val container = binding!!.profiles
|
|
container.removeAllViews()
|
|
store.load().profiles.forEach { profile ->
|
|
container.addView(Button(requireContext()).apply {
|
|
text = profile.name + "\n" + profileSummary(profile)
|
|
isAllCaps = false
|
|
setOnClickListener { showEditor(profile) }
|
|
})
|
|
}
|
|
}
|
|
|
|
private fun showEditor(existing: AlertProfile? = null) {
|
|
selectedSoundUri = existing?.soundUri
|
|
val context = requireContext()
|
|
val form = LinearLayout(context).apply {
|
|
orientation = LinearLayout.VERTICAL
|
|
setPadding(dp(24), 0, dp(24), 0)
|
|
}
|
|
val name = EditText(context).apply {
|
|
hint = "Profile name"
|
|
setText(existing?.name)
|
|
}
|
|
val vibration = EditText(context).apply {
|
|
hint = "Vibration timing in milliseconds, for example 0, 200, 100, 200"
|
|
setText(existing?.vibrationPattern?.joinToString(", ") ?: "0, 200")
|
|
inputType = android.text.InputType.TYPE_CLASS_TEXT
|
|
}
|
|
val pickerButton = Button(context).apply {
|
|
text = if (selectedSoundUri == null) "Choose sound" else "Change sound"
|
|
setOnClickListener {
|
|
chooseSound.launch(
|
|
Intent(RingtoneManager.ACTION_RINGTONE_PICKER)
|
|
.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION)
|
|
.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, selectedSoundUri?.let(Uri::parse)),
|
|
)
|
|
}
|
|
}
|
|
soundButton = pickerButton
|
|
form.addView(name)
|
|
form.addView(pickerButton)
|
|
form.addView(vibration)
|
|
val dialog = MaterialAlertDialogBuilder(context)
|
|
.setTitle(if (existing == null) "Add profile" else "Edit profile")
|
|
.setView(form)
|
|
.setNegativeButton("Cancel", null)
|
|
.setPositiveButton("Save", null)
|
|
.apply {
|
|
if (existing != null) setNeutralButton("Delete", null)
|
|
}
|
|
.show()
|
|
dialog.getButton(android.content.DialogInterface.BUTTON_POSITIVE).setOnClickListener {
|
|
val pattern = parsePattern(vibration.text.toString()) ?: run {
|
|
vibration.error = "Use non-negative comma-separated milliseconds"
|
|
return@setOnClickListener
|
|
}
|
|
val profileName = name.text.toString().trim()
|
|
if (profileName.isEmpty() || selectedSoundUri == null && pattern.none { it > 0 }) {
|
|
name.error = if (profileName.isEmpty()) "Enter a name" else null
|
|
vibration.error = if (selectedSoundUri == null && pattern.none { it > 0 }) "Choose a sound or vibration" else null
|
|
return@setOnClickListener
|
|
}
|
|
val profile = AlertProfile(existing?.id ?: UUID.randomUUID().toString(), profileName, selectedSoundUri, pattern)
|
|
val configuration = store.load()
|
|
store.save(configuration.copy(profiles = configuration.profiles.filterNot { it.id == profile.id } + profile))
|
|
dialog.dismiss()
|
|
refresh()
|
|
}
|
|
if (existing != null) {
|
|
dialog.getButton(android.content.DialogInterface.BUTTON_NEUTRAL).setOnClickListener {
|
|
val configuration = store.load()
|
|
if (configuration.rules.any { it.profileId == existing.id }) {
|
|
Toast.makeText(context, "Remove or change rules using this profile first", Toast.LENGTH_LONG).show()
|
|
return@setOnClickListener
|
|
}
|
|
store.save(configuration.copy(profiles = configuration.profiles.filterNot { it.id == existing.id }))
|
|
dialog.dismiss()
|
|
refresh()
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun parsePattern(text: String): List<Long>? = text.split(',')
|
|
.map { it.trim() }
|
|
.filter { it.isNotEmpty() }
|
|
.map { it.toLongOrNull() ?: return null }
|
|
.takeIf { it.all { value -> value >= 0 } }
|
|
?: emptyList()
|
|
|
|
private fun profileSummary(profile: AlertProfile): String = buildList {
|
|
if (profile.soundUri != null) add("Sound")
|
|
if (profile.vibrationPattern.any { it > 0 }) add("Vibration")
|
|
}.joinToString(" + ")
|
|
|
|
private fun dp(value: Int) = (value * resources.displayMetrics.density).toInt()
|
|
}
|