H-PixelDroid/PixelDroid

View on GitHub
app/src/main/java/org/pixeldroid/app/profile/EditProfileActivity.kt

Summary

Maintainability
D
2 days
Test Coverage
package org.pixeldroid.app.profile

import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.View
import androidx.activity.addCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.core.widget.doAfterTextChanged
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.launch
import org.pixeldroid.app.R
import org.pixeldroid.app.databinding.ActivityEditProfileBinding
import org.pixeldroid.app.utils.BaseActivity
import org.pixeldroid.app.utils.openUrl

class EditProfileActivity : BaseActivity() {

    private val model: EditProfileViewModel by viewModels()
    private lateinit var binding: ActivityEditProfileBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityEditProfileBinding.inflate(layoutInflater)
        setContentView(binding.root)
        setSupportActionBar(binding.topBar)
        supportActionBar?.setDisplayHomeAsUpEnabled(true)

        onBackPressedDispatcher.addCallback(this) {
            // Handle the back button event
            if(model.madeChanges()){
                MaterialAlertDialogBuilder(binding.root.context).apply {
                    setMessage(getString(R.string.profile_save_changes))
                    setNegativeButton(android.R.string.cancel) { _, _ -> }
                    setPositiveButton(android.R.string.ok) { _, _ ->
                        this@addCallback.isEnabled = false
                        super.onBackPressedDispatcher.onBackPressed()
                    }
                }.show()
            } else {
                this.isEnabled = false
                if (model.submittedChanges) setResult(RESULT_OK)
                super.onBackPressedDispatcher.onBackPressed()
            }
        }

        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                model.uiState.collect { uiState ->
                    if(binding.bioEditText.text.toString() != uiState.bio) binding.bioEditText.setText(uiState.bio)
                    if(binding.nameEditText.text.toString() != uiState.name) binding.nameEditText.setText(uiState.name)

                    binding.progressCard.visibility = if(uiState.loadingProfile || uiState.sendingProfile || uiState.uploadingPicture || uiState.profileSent || uiState.error) View.VISIBLE else View.INVISIBLE

                    if(uiState.loadingProfile) binding.progressText.setText(R.string.fetching_profile)
                    else if(uiState.sendingProfile) binding.progressText.setText(R.string.saving_profile)

                    binding.privateSwitch.isChecked = uiState.privateAccount == true
                    Glide.with(binding.profilePic).load(uiState.profilePictureUri)
                        .apply(RequestOptions.circleCropTransform())
                        .into(binding.profilePic)

                    binding.savingProgressBar.visibility =
                        if(uiState.error || (uiState.profileSent && !uiState.uploadingPicture)) View.GONE
                    else View.VISIBLE

                    if(uiState.profileSent && !uiState.uploadingPicture && !uiState.error){
                        binding.progressText.setText(R.string.profile_saved)
                        binding.done.visibility = View.VISIBLE
                    } else {
                        binding.done.visibility = View.GONE
                    }
                    if(uiState.error){
                        binding.progressText.setText(R.string.error_profile)
                        binding.error.visibility = View.VISIBLE
                    } else binding.error.visibility = View.GONE

                }
            }
        }
        binding.bioEditText.doAfterTextChanged {
            model.updateBio(binding.bioEditText.text)
        }
        binding.nameEditText.doAfterTextChanged {
            model.updateName(binding.nameEditText.text)
        }
        binding.privateSwitch.setOnCheckedChangeListener { _, isChecked ->
            model.updatePrivate(isChecked)
        }

        binding.progressCard.setOnClickListener {
            model.clickedCard()
        }

        binding.editButton.setOnClickListener {
            val domain = db.userDao().getActiveUser()!!.instance_uri
            val url = "$domain/settings/home"

            if(!openUrl(url)) {
                Snackbar.make(binding.root, getString(R.string.edit_link_failed),
                    Snackbar.LENGTH_LONG).show()
            }
        }

        binding.profilePic.setOnClickListener {
            Intent(Intent.ACTION_GET_CONTENT).apply {
                type = "*/*"
                putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("image/*"))
                action = Intent.ACTION_GET_CONTENT
                addCategory(Intent.CATEGORY_OPENABLE)
                putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false)
                uploadImageResultContract.launch(
                    Intent.createChooser(this, null)
                )
            }
        }
    }

    private val uploadImageResultContract = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        val data: Intent? = result.data
        if (result.resultCode == Activity.RESULT_OK && data != null) {
            val images: ArrayList<String> = ArrayList()
            val clipData = data.clipData
            if (clipData != null) {
                val count = clipData.itemCount
                for (i in 0 until count) {
                    val imageUri: String = clipData.getItemAt(i).uri.toString()
                    images.add(imageUri)
                }
                model.updateImage(images.first())
            } else if (data.data != null) {
                images.add(data.data!!.toString())
                model.updateImage(images.first())
            }
        }
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        menuInflater.inflate(R.menu.edit_profile_menu, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.itemId){
            R.id.action_apply -> {
                model.sendProfile()
                return true
            }
        }
        return super.onOptionsItemSelected(item)
    }
}