238 lines
9.4 KiB
Kotlin
238 lines
9.4 KiB
Kotlin
package pro.nnnteam.nnnet
|
|
|
|
import android.os.Build
|
|
import android.os.Bundle
|
|
import android.widget.EditText
|
|
import android.widget.ImageButton
|
|
import android.widget.TextView
|
|
import android.widget.Toast
|
|
import androidx.appcompat.app.AppCompatActivity
|
|
import androidx.lifecycle.lifecycleScope
|
|
import com.google.android.material.button.MaterialButton
|
|
import com.google.android.material.switchmaterial.SwitchMaterial
|
|
import kotlinx.coroutines.launch
|
|
import pro.nnnteam.nnnet.data.MeshDatabase
|
|
import pro.nnnteam.nnnet.data.MeshRepository
|
|
import pro.nnnteam.nnnet.data.ProfileEntity
|
|
import pro.nnnteam.nnnet.mesh.MeshServiceContract
|
|
import pro.nnnteam.nnnet.update.UpdateInfo
|
|
import pro.nnnteam.nnnet.update.UpdateManager
|
|
import android.content.BroadcastReceiver
|
|
import android.content.Intent
|
|
import android.content.IntentFilter
|
|
|
|
class SettingsActivity : AppCompatActivity() {
|
|
private lateinit var repository: MeshRepository
|
|
private lateinit var firstNameInput: EditText
|
|
private lateinit var lastNameInput: EditText
|
|
private lateinit var usernameInput: EditText
|
|
private lateinit var descriptionInput: EditText
|
|
private lateinit var searchInput: EditText
|
|
private lateinit var profileResultCard: android.view.View
|
|
private lateinit var resultNameText: TextView
|
|
private lateinit var resultUsernameText: TextView
|
|
private lateinit var resultDescriptionText: TextView
|
|
private lateinit var resultPeerIdText: TextView
|
|
|
|
private var receiverRegistered = false
|
|
|
|
private val prefs by lazy {
|
|
getSharedPreferences(UpdateManager.PREFS_NAME, MODE_PRIVATE)
|
|
}
|
|
|
|
private val meshEventReceiver = object : BroadcastReceiver() {
|
|
override fun onReceive(context: android.content.Context?, intent: Intent?) {
|
|
if (intent?.action != MeshServiceContract.ACTION_EVENT) return
|
|
val eventType = intent.getStringExtra(MeshServiceContract.EXTRA_EVENT_TYPE) ?: return
|
|
if (eventType == MeshServiceContract.EVENT_PROFILES_CHANGED) {
|
|
val query = searchInput.text.toString().trim()
|
|
if (query.isNotEmpty()) {
|
|
lookupProfile(query)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
super.onCreate(savedInstanceState)
|
|
setContentView(R.layout.activity_settings)
|
|
|
|
val database = MeshDatabase.getInstance(applicationContext)
|
|
repository = MeshRepository(database.messageDao(), database.outboundQueueDao(), database.profileDao())
|
|
|
|
findViewById<ImageButton>(R.id.backButton).setOnClickListener { finish() }
|
|
|
|
firstNameInput = findViewById(R.id.firstNameInput)
|
|
lastNameInput = findViewById(R.id.lastNameInput)
|
|
usernameInput = findViewById(R.id.usernameInput)
|
|
descriptionInput = findViewById(R.id.descriptionInput)
|
|
searchInput = findViewById(R.id.searchInput)
|
|
profileResultCard = findViewById(R.id.profileResultCard)
|
|
resultNameText = findViewById(R.id.resultNameText)
|
|
resultUsernameText = findViewById(R.id.resultUsernameText)
|
|
resultDescriptionText = findViewById(R.id.resultDescriptionText)
|
|
resultPeerIdText = findViewById(R.id.resultPeerIdText)
|
|
|
|
val autoUpdateSwitch = findViewById<SwitchMaterial>(R.id.autoUpdateSwitch)
|
|
val versionText = findViewById<TextView>(R.id.versionText)
|
|
autoUpdateSwitch.isChecked = prefs.getBoolean(UpdateManager.KEY_AUTO_UPDATE, false)
|
|
autoUpdateSwitch.setOnCheckedChangeListener { _, isChecked ->
|
|
prefs.edit().putBoolean(UpdateManager.KEY_AUTO_UPDATE, isChecked).apply()
|
|
}
|
|
|
|
versionText.text = getString(
|
|
R.string.current_version,
|
|
packageManager.getPackageInfo(packageName, 0).versionName,
|
|
currentVersionCode()
|
|
)
|
|
|
|
findViewById<MaterialButton>(R.id.saveProfileButton).setOnClickListener { saveProfile() }
|
|
findViewById<MaterialButton>(R.id.searchButton).setOnClickListener {
|
|
val query = searchInput.text.toString().trim()
|
|
if (query.isEmpty()) {
|
|
Toast.makeText(this, R.string.enter_username_to_search, Toast.LENGTH_SHORT).show()
|
|
} else {
|
|
lookupProfile(query)
|
|
}
|
|
}
|
|
findViewById<MaterialButton>(R.id.checkUpdatesButton).setOnClickListener { checkForUpdates() }
|
|
|
|
loadLocalProfile()
|
|
}
|
|
|
|
override fun onStart() {
|
|
super.onStart()
|
|
registerMeshReceiver()
|
|
}
|
|
|
|
override fun onStop() {
|
|
if (receiverRegistered) {
|
|
unregisterReceiver(meshEventReceiver)
|
|
receiverRegistered = false
|
|
}
|
|
super.onStop()
|
|
}
|
|
|
|
private fun registerMeshReceiver() {
|
|
if (receiverRegistered) return
|
|
val filter = IntentFilter(MeshServiceContract.ACTION_EVENT)
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
registerReceiver(meshEventReceiver, filter, RECEIVER_NOT_EXPORTED)
|
|
} else {
|
|
@Suppress("DEPRECATION")
|
|
registerReceiver(meshEventReceiver, filter)
|
|
}
|
|
receiverRegistered = true
|
|
}
|
|
|
|
private fun loadLocalProfile() {
|
|
lifecycleScope.launch {
|
|
val localProfile = repository.localProfile()
|
|
if (localProfile != null) {
|
|
firstNameInput.setText(localProfile.firstName)
|
|
lastNameInput.setText(localProfile.lastName)
|
|
usernameInput.setText(localProfile.username)
|
|
descriptionInput.setText(localProfile.description)
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun saveProfile() {
|
|
val firstName = firstNameInput.text.toString().trim()
|
|
val lastName = lastNameInput.text.toString().trim()
|
|
val username = usernameInput.text.toString().trim().removePrefix("@")
|
|
val description = descriptionInput.text.toString().trim()
|
|
|
|
if (username.isBlank()) {
|
|
Toast.makeText(this, R.string.username_required, Toast.LENGTH_SHORT).show()
|
|
return
|
|
}
|
|
|
|
lifecycleScope.launch {
|
|
repository.saveLocalProfile(
|
|
firstName = firstName,
|
|
lastName = lastName,
|
|
username = username,
|
|
description = description
|
|
)
|
|
Toast.makeText(this@SettingsActivity, R.string.profile_saved, Toast.LENGTH_SHORT).show()
|
|
}
|
|
}
|
|
|
|
private fun lookupProfile(username: String) {
|
|
lifecycleScope.launch {
|
|
val profile = repository.profileByUsername(username.removePrefix("@"))
|
|
renderSearchResult(profile)
|
|
if (profile == null) {
|
|
Toast.makeText(this@SettingsActivity, R.string.profile_not_found_locally, Toast.LENGTH_SHORT).show()
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun renderSearchResult(profile: ProfileEntity?) {
|
|
if (profile == null) {
|
|
profileResultCard.visibility = android.view.View.GONE
|
|
return
|
|
}
|
|
profileResultCard.visibility = android.view.View.VISIBLE
|
|
resultNameText.text = profile.displayName()
|
|
resultUsernameText.text = "@${profile.username}"
|
|
resultDescriptionText.text = profile.description.ifBlank { getString(R.string.no_profile_description) }
|
|
resultPeerIdText.text = if (profile.peerId.isBlank()) {
|
|
getString(R.string.peer_id_unknown)
|
|
} else {
|
|
getString(R.string.peer_id_value, profile.peerId)
|
|
}
|
|
}
|
|
|
|
private fun checkForUpdates() {
|
|
lifecycleScope.launch {
|
|
val updateInfo = kotlinx.coroutines.withContext(kotlinx.coroutines.Dispatchers.IO) { UpdateManager.fetchUpdateInfo() }
|
|
if (updateInfo == null) {
|
|
Toast.makeText(this@SettingsActivity, R.string.update_check_failed, Toast.LENGTH_SHORT).show()
|
|
return@launch
|
|
}
|
|
if (updateInfo.versionCode > currentVersionCode()) {
|
|
showUpdateDialog(updateInfo)
|
|
} else {
|
|
Toast.makeText(this@SettingsActivity, R.string.latest_version_installed, Toast.LENGTH_SHORT).show()
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun showUpdateDialog(updateInfo: UpdateInfo) {
|
|
lifecycleScope.launch {
|
|
val releaseNotes = kotlinx.coroutines.withContext(kotlinx.coroutines.Dispatchers.IO) {
|
|
UpdateManager.fetchReleaseNotes(updateInfo.releaseNotesPath)
|
|
}
|
|
androidx.appcompat.app.AlertDialog.Builder(this@SettingsActivity)
|
|
.setTitle(updateInfo.releaseNotesTitle)
|
|
.setMessage(
|
|
buildString {
|
|
append(getString(R.string.update_available_message, updateInfo.versionName))
|
|
if (!releaseNotes.isNullOrBlank()) {
|
|
append("\n\n")
|
|
append(releaseNotes.trim())
|
|
}
|
|
}
|
|
)
|
|
.setPositiveButton(R.string.download_update) { _, _ ->
|
|
val url = UpdateManager.buildDownloadUrl(updateInfo.apkPath)
|
|
startActivity(Intent(Intent.ACTION_VIEW, android.net.Uri.parse(url)))
|
|
}
|
|
.setNegativeButton(R.string.later, null)
|
|
.show()
|
|
}
|
|
}
|
|
|
|
private fun currentVersionCode(): Int {
|
|
val packageInfo = packageManager.getPackageInfo(packageName, 0)
|
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
packageInfo.longVersionCode.toInt()
|
|
} else {
|
|
@Suppress("DEPRECATION")
|
|
packageInfo.versionCode
|
|
}
|
|
}
|
|
}
|