SDPTeam15/PolyEvents

View on GitHub
app/src/main/java/com/github/sdpteam15/polyevents/view/activity/admin/ZoneManagementActivity.kt

Summary

Maintainability
A
0 mins
Test Coverage
A
90%
package com.github.sdpteam15.polyevents.view.activity.admin

import android.os.Bundle
import android.view.MenuItem
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.FrameLayout
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.github.sdpteam15.polyevents.R
import com.github.sdpteam15.polyevents.helper.HelperFunctions
import com.github.sdpteam15.polyevents.model.database.remote.Database.currentDatabase
import com.github.sdpteam15.polyevents.model.entity.Zone
import com.github.sdpteam15.polyevents.model.map.GoogleMapHelper
import com.github.sdpteam15.polyevents.model.map.MapsFragmentMod
import com.github.sdpteam15.polyevents.model.map.ZoneAreaMapHelper
import com.github.sdpteam15.polyevents.model.observable.Observable
import com.github.sdpteam15.polyevents.view.activity.admin.ZoneManagementListActivity.Companion.EXTRA_ID
import com.github.sdpteam15.polyevents.view.activity.admin.ZoneManagementListActivity.Companion.NEW_ZONE
import com.github.sdpteam15.polyevents.view.fragments.MapsFragment

/**
 * Activity to manage a zone
 */
class ZoneManagementActivity : AppCompatActivity() {
    companion object {
        var zoneObservable = Observable<Zone>()
        val zone = Zone(location = "")
        var zoneId = ""
        var zoneStateLocation: String? = null
        var inTest = false
    }

    val etName
        get() = findViewById<EditText>(R.id.id_zone_management_name_edittext)
    val etDesc
        get() = findViewById<EditText>(R.id.id_zone_management_description_edittext)
    val etLoc
        get() = findViewById<EditText>(R.id.id_zone_management_coordinates_edittext)
    val btnManage
        get() = findViewById<Button>(R.id.id_btn_manage)
    val btnManageCoor
        get() = findViewById<Button>(R.id.id_btn_modify_coordinates)
    val btnDelete
        get() = findViewById<Button>(R.id.id_btn_delete_coordinates)
    val tvManage
        get() = findViewById<TextView>(R.id.id_tv_manage)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_zone_management)
        supportActionBar!!.setDisplayHomeAsUpEnabled(true)
        //Get the views needed in the code
        val int = intent
        zoneId = int.getStringExtra(EXTRA_ID).toString()
        val mapFragment = MapsFragment(MapsFragmentMod.EditZone)
        ZoneAreaMapHelper.zone = zone
        zoneObservable = Observable()

        zoneObservable.observe(this) {
            //Reactive the back button and make the map fragment invisible
            supportActionBar!!.setDisplayHomeAsUpEnabled(true)
            findViewById<FrameLayout>(R.id.id_framelayout_map_edit_zone).visibility = View.INVISIBLE
            //Set the retrieve texts in the fields
            val zoneInfo = it.value
            etName.setText(zoneInfo.zoneName)
            etDesc.setText(zoneInfo.description)
            changeCoordinatesText(etLoc, btnManageCoor, btnDelete, zoneInfo.location)
        }
        zoneObservable.observeOnce(this) {
            zone.location = it.value.location
            zoneStateLocation = it.value.location
        }

        if (zoneId == NEW_ZONE) {
            zoneId = "Zone ${GoogleMapHelper.uidZone++}"
            ZoneAreaMapHelper.zonesToArea[zoneId] = Pair(null, mutableListOf())
            // Create a new zone, setup the text of the button consequently
            changeCoordinatesText(etLoc, btnManageCoor, btnDelete, "")
            btnManage.text = this.getString(R.string.btn_create_zone_button_text)
            tvManage.text = this.getString(R.string.tv_create_zone_text)
            //Click on manage create a new zone
            btnManage.setOnClickListener {
                createZone()
            }
        } else {
            // Manage an existing zone, setup the text of the button consequently
            changeCoordinatesText(etLoc, btnManageCoor, btnDelete, zoneId)
            btnManage.text = this.getString(R.string.btn_update_zone_button_text)
            tvManage.text = this.getString(R.string.tv_update_zone_text)

            val infoGotten = Observable<Boolean>()
            // Get the zone information in the database
            currentDatabase.zoneDatabase.getZoneInformation(zoneId, zoneObservable).updateOnce(
                this,
                infoGotten
            )
            // Add a progress dialog to wait for the transaction with the database to be over
            HelperFunctions.showProgressDialog(this, listOf(infoGotten), supportFragmentManager)

            // Click on manage update the zone
            btnManage.setOnClickListener {
                updateZoneInfo()
            }
        }

        ZoneAreaMapHelper.editingZone = zoneId
        setupListener(mapFragment)
    }

    /**
     * Method that will set the listener on the buttons properly
     * @param mapFragment: The map fragment object
     */
    private fun setupListener(
        mapFragment: MapsFragment
    ) {
        btnDelete.setOnClickListener {
            //reset the location field text
            zone.location = ""
            ZoneAreaMapHelper.removeZoneAreas(ZoneAreaMapHelper.editingZone!!)
            //Set the correct text and visibility on the buttons
            changeCoordinatesText(etLoc, btnManageCoor, btnDelete, "")
        }
        btnManageCoor.setOnClickListener {

            //display the FrameLayout that will contain the map fragment
            findViewById<FrameLayout>(R.id.id_framelayout_map_edit_zone).visibility = View.VISIBLE

            //Set the currently set information
            zone.description = etDesc.text.toString()
            zone.zoneName = etName.text.toString()
            //TODO add the area to be modified (once the zone modifier is implemented)
            //disable the back button in the navigation bar to avoid confusion
            supportActionBar!!.setDisplayHomeAsUpEnabled(false)
            //Avoid displaying the map in tests, this makes Cirrus crash
            if (!inTest)
                HelperFunctions.changeFragment(this, mapFragment, R.id.id_framelayout_map_edit_zone)
        }
    }

    /**
     * Change the text of the coordinates  field
     * @param locationText: The location text we should inspect
     */
    private fun changeCoordinatesText(
        etLoc: EditText,
        btnManage: Button,
        btnDelete: Button,
        locationText: String?
    ) {
        val text: String
        if (locationText == null || locationText == "") {
            //If the location is not currently set, delete button invisible and set the correct text
            text = getString(R.string.zone_management_coordinates_not_set)
            btnManage.text = getString(R.string.btn_modify_coord_set_text)
            btnDelete.visibility = View.INVISIBLE
        } else {
            //If the location is currently set, delete button visible and set the correct text
            btnManage.text = getString(R.string.btn_modify_coord_update_text)
            btnDelete.visibility = View.VISIBLE
            text = getString(R.string.zone_management_coordinates_set)
        }

        etLoc.setText(text)
    }

    /**
     * Handle the zone creation event
     */
    private fun createZone() {
        //Create a new zone based on the fields
        val name = etName.text.toString()
        val desc = etDesc.text.toString()
        val loc = etLoc.text.toString()

        //check if the strings are all set properly
        if (checkNotEmpty(name, loc, desc)) {
            //set the correct information
            zone.description = desc
            zone.zoneName = name
            //zoneId is null to create a new Area
            zone.zoneId = null
            val createOver = Observable<Boolean>()
            currentDatabase.zoneDatabase.createZone(zone).observe(this) {
                callbackHandler(
                    it.value,
                    this.getString(R.string.zone_added_successfully),
                    this.getString(R.string.zone_add_fail)
                )
            }.then.updateOnce(this, createOver)
            // Add a progress dialog to wait for the transaction with the database to be over
            HelperFunctions.showProgressDialog(this, listOf(createOver), supportFragmentManager)
        }
    }

    /**
     * Handle the zone update event
     */
    private fun updateZoneInfo() {
        //Update zone information based on the fields
        val name = etName.text.toString()
        val desc = etDesc.text.toString()
        val loc = etLoc.text.toString()
        if (checkNotEmpty(name, loc, desc)) {
            //set the correct information
            zone.description = desc
            zone.zoneName = name
            zone.zoneId = zoneId

            if (zone.location != zoneStateLocation)
                currentDatabase.routeDatabase.removeEdgeConnectedToZone(zone)


            val updateOver = Observable<Boolean>()
            currentDatabase.zoneDatabase.updateZoneInformation(zoneId, zone).observe {
                callbackHandler(
                    it.value,
                    this.getString(R.string.zone_updated_successfully),
                    this.getString(R.string.zone_update_fail)
                )
            }.then.updateOnce(this, updateOver)
            // Add a progress dialog to wait for the transaction with the database to be over
            HelperFunctions.showProgressDialog(this, listOf(updateOver), supportFragmentManager)
        }
    }

    /**
     * This method handle the callback from the creation and update method of the database
     * @param it: The return value from the database
     * @param successMessage: the message to display in case of success
     * @param failMessage: The message to display in case of failure
     */
    private fun callbackHandler(it: Boolean?, successMessage: String, failMessage: String) {
        if (it!!) {
            //Show a toast indicating that the area was successfully created and redirect to the correct activity
            HelperFunctions.showToast(
                successMessage,
                this
            )
            etDesc.setText("")
            etName.setText("")
            etLoc.setText("")
            ZoneAreaMapHelper.removeZone(zoneId)
            finish()
        } else {
            //show a toast indicating that there was an error and stay on this activity
            HelperFunctions.showToast(failMessage, this)
        }
    }

    /**
     * @param name : the name entered in the zoneName field
     * @param loc : text in the zoneCoord text
     * @param desc : the description entered in the zoneDesc field
     * @return true if the string are correctly set, false otherwise
     */
    private fun checkNotEmpty(name: String, loc: String?, desc: String): Boolean {
        if (name == "" || desc == "" || loc == getString(R.string.zone_management_coordinates_not_set)) {
            //Show a small message that invite the user to try again
            HelperFunctions.showToast(this.getString(R.string.missing_field_zone_management), this)
            return false
        }
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        val id = item.itemId
        //handles the back arrow as the back button of the phone
        if (id == android.R.id.home) {
            onBackPressed()
        }
        return true
    }


    override fun onBackPressed() {
        super.onBackPressed()
        //Goes to the database to get the zone as it was before modification
        ZoneAreaMapHelper.removeZone(zoneId)
        val obs: Observable<Zone> = Observable()
        obs.observe {
            ZoneAreaMapHelper.waitingZones.add(it.value)
        }

        // To refresh the local cache
        currentDatabase.zoneDatabase.getZoneInformation(zoneId, obs)
    }
}