H-PixelDroid/PixelDroid

View on GitHub
app/src/main/java/org/pixeldroid/app/postCreation/PostSubmissionFragment.kt

Summary

Maintainability
D
1 day
Test Coverage
package org.pixeldroid.app.postCreation

import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.activity.OnBackPressedCallback
import androidx.core.view.MenuProvider
import androidx.core.widget.doAfterTextChanged
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.fragment.findNavController
import androidx.navigation.ui.setupWithNavController
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.launch
import org.pixeldroid.app.R
import org.pixeldroid.app.databinding.FragmentPostSubmissionBinding
import org.pixeldroid.app.postCreation.camera.CameraFragment
import org.pixeldroid.app.utils.BaseFragment
import org.pixeldroid.app.utils.bindingLifecycleAware
import org.pixeldroid.app.utils.db.entities.InstanceDatabaseEntity
import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity
import org.pixeldroid.app.utils.setSquareImageFromURL
import kotlin.math.roundToInt


class PostSubmissionFragment : BaseFragment() {

    private lateinit var accounts: List<UserDatabaseEntity>
    private var selectedAccount: Int = -1

    private var user: UserDatabaseEntity? = null
    private lateinit var instance: InstanceDatabaseEntity

    private var binding: FragmentPostSubmissionBinding by bindingLifecycleAware()
    private val model: PostCreationViewModel by activityViewModels()

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        super.onCreateView(inflater, container, savedInstanceState)

        // Inflate the layout for this fragment
        binding = FragmentPostSubmissionBinding.inflate(layoutInflater)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        binding.topBar.setupWithNavController(findNavController())

        user = db.userDao().getActiveUser()
        accounts = db.userDao().getAll()

        instance = user?.run {
            db.instanceDao().getInstance(instance_uri)
        } ?: InstanceDatabaseEntity("", "")

        // Display the values from the view model
        binding.nsfwSwitch.isChecked = model.uiState.value.nsfw
        binding.newPostDescriptionInputField.setText(model.uiState.value.newPostDescriptionText)

        if(model.uiState.value.storyCreation){
            binding.nsfwSwitch.visibility = View.GONE
            binding.postTextInputLayout.visibility = View.GONE
            binding.privateTitle.visibility = View.GONE
            binding.postPreview.visibility = View.GONE

            binding.storyOptions.visibility = View.VISIBLE
            binding.storyDurationSlider.value = model.uiState.value.storyDuration.toFloat()
            binding.storyRepliesSwitch.isChecked = model.uiState.value.storyReplies
            binding.storyReactionsSwitch.isChecked = model.uiState.value.storyReactions
        }

        lifecycleScope.launch {
            viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                model.uiState.collect { uiState ->
                    uiState.userMessage?.let {
                        MaterialAlertDialogBuilder(binding.root.context)
                            .setMessage(it)
                            .setNegativeButton(android.R.string.ok) { _, _ -> }
                            .show()

                        // Notify the ViewModel the message is displayed
                        model.userMessageShown()
                    }
                    enableButton(uiState.postCreationSendButtonEnabled)
                    binding.uploadProgressBar.visibility =
                        if (uiState.uploadProgressBarVisible) View.VISIBLE else View.INVISIBLE
                    binding.uploadProgressBar.progress = uiState.uploadProgress
                    binding.uploadCompletedTextview.visibility =
                        if (uiState.uploadCompletedTextviewVisible) View.VISIBLE else View.INVISIBLE
                    binding.uploadError.visibility =
                        if (uiState.uploadErrorVisible) View.VISIBLE else View.INVISIBLE
                    binding.uploadErrorTextExplanation.visibility =
                        if (uiState.uploadErrorExplanationVisible) View.VISIBLE else View.INVISIBLE

                    selectedAccount = accounts.indexOf(uiState.chosenAccount)

                    binding.uploadErrorTextExplanation.text = uiState.uploadErrorExplanationText
                }
            }
        }

        binding.newPostDescriptionInputField.doAfterTextChanged {
            model.newPostDescriptionChanged(binding.newPostDescriptionInputField.text)
        }

        binding.nsfwSwitch.setOnCheckedChangeListener { _, isChecked ->
            model.updateNSFW(isChecked)
        }
        binding.storyRepliesSwitch.setOnCheckedChangeListener { _, isChecked ->
            model.updateStoryReplies(isChecked)
        }
        binding.storyReactionsSwitch.setOnCheckedChangeListener { _, isChecked ->
            model.updateStoryReactions(isChecked)
        }

        binding.postTextInputLayout.counterMaxLength = instance.maxStatusChars

        binding.storyDurationSlider.addOnChangeListener { _, value, _ ->
            // Responds to when slider's value is changed
            model.storyDuration(value.roundToInt())
        }

        setSquareImageFromURL(View(requireActivity()), model.getPhotoData().value?.get(0)?.imageUri.toString(), binding.postPreview)

        // Get the description and send the post
        binding.postSubmissionSendButton.setOnClickListener {
            if (validatePost()) model.upload()
        }

        // Button to retry image upload when it fails
        binding.retryUploadButton.setOnClickListener {
            model.resetUploadStatus()
            model.upload()
        }

        // Handle back pressed button
        requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                findNavController().navigate(R.id.action_postSubmissionFragment_to_postCreationFragment)
            }
        })

        binding.topBar.addMenuProvider(object: MenuProvider {
            override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
                // Add menu items here
                menuInflater.inflate(R.menu.post_submission_account_menu, menu)
            }

            override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
                // Handle the menu selection
                return when (menuItem.itemId) {
                    R.id.action_switch_accounts -> {
                        MaterialAlertDialogBuilder(requireActivity()).apply {
                            setIcon(R.drawable.switch_account)
                            setTitle(R.string.switch_accounts)
                            setSingleChoiceItems(accounts.map { it.username + " (${it.fullHandle})" }.toTypedArray(), selectedAccount) { dialog, which ->
                                if (selectedAccount != which) {
                                    model.chooseAccount(accounts[which])
                                }
                                dialog.dismiss()
                            }
                            setNegativeButton(android.R.string.cancel) { _, _ -> }
                        }.show()
                        return true
                    }
                    else -> false
                }
            }
        }, viewLifecycleOwner, Lifecycle.State.RESUMED)
    }

    private fun validatePost(): Boolean {
        binding.postTextInputLayout.run {
            val content = editText?.length() ?: 0
            if (content > counterMaxLength) {
                // error, too many characters
                error = resources.getQuantityString(R.plurals.description_max_characters, counterMaxLength, counterMaxLength)
                return false
            }
        }
        return true
    }

    private fun enableButton(enable: Boolean = true){
        binding.postSubmissionSendButton.isEnabled = enable
        if(enable){
            binding.postingProgressBar.visibility = View.GONE
            binding.postSubmissionSendButton.visibility = View.VISIBLE
        } else {
            binding.postingProgressBar.visibility = View.VISIBLE
            binding.postSubmissionSendButton.visibility = View.GONE
        }
    }

}