app/src/main/java/com/github/sdpteam15/polyevents/view/activity/admin/ItemRequestManagementActivity.kt
package com.github.sdpteam15.polyevents.view.activity.admin
import android.annotation.SuppressLint
import android.content.Context
import android.os.Bundle
import android.transition.Slide
import android.transition.TransitionManager
import android.view.Gravity
import android.view.LayoutInflater
import android.widget.Button
import android.widget.LinearLayout
import android.widget.PopupWindow
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
import com.github.sdpteam15.polyevents.R
import com.github.sdpteam15.polyevents.helper.DatabaseHelper.addToUsersFromDB
import com.github.sdpteam15.polyevents.helper.HelperFunctions
import com.github.sdpteam15.polyevents.model.database.remote.Database.currentDatabase
import com.github.sdpteam15.polyevents.model.entity.Event
import com.github.sdpteam15.polyevents.model.entity.Item
import com.github.sdpteam15.polyevents.model.entity.MaterialRequest
import com.github.sdpteam15.polyevents.model.entity.Zone
import com.github.sdpteam15.polyevents.model.observable.Observable
import com.github.sdpteam15.polyevents.model.observable.ObservableList
import com.github.sdpteam15.polyevents.model.observable.ObservableMap
import com.github.sdpteam15.polyevents.view.adapter.ItemRequestAdminAdapter
/**
* Activity to display item requests to Admins
*/
class ItemRequestManagementActivity : AppCompatActivity() {
private lateinit var recyclerView: RecyclerView
private val requests = ObservableList<MaterialRequest>()
private val userNames = ObservableMap<String, String>()
private val itemNames = ObservableMap<String, String>()
private val zoneNameFromEventId = ObservableMap<String, String>()
private val items = ObservableList<Triple<Item, Int, Int>>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_item_request_management)
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
recyclerView = findViewById(R.id.id_recycler_item_requests)
requests.observeAdd(this) {
if (!userNames.containsKey(it.value.userId)) {
addToUsersFromDB(it.value.userId, userNames, this, this)
}
if (it.value.staffInChargeId != null && !userNames.containsKey(it.value.staffInChargeId!!)) {
addToUsersFromDB(it.value.staffInChargeId!!, userNames, this, this)
}
}
items.group(this) { it.first.itemId!! }.then.map(this, itemNames) {
it[0].first.itemName!!
}
recyclerView.adapter =
ItemRequestAdminAdapter(
this,
this,
requests,
userNames,
itemNames,
zoneNameFromEventId,
acceptMaterialRequest,
declineMaterialRequest
)
//Wait until we have both requests accepted from the database to show the material requests
val matListTransactionOver = currentDatabase.materialRequestDatabase.getMaterialRequestList(
requests.sortAndLimitFrom(this) { it.status })
.observeOnce(this) { it ->
if (!it.value) {
HelperFunctions.showToast("Failed to get the list of material requests", this)
} else {
// List that will contain all the observable that need a value for the loading screen to dismiss
val allLoading = ArrayList<Observable<*>>()
val itemListTransactionOver = currentDatabase.itemDatabase.getItemsList(items)
.observeOnce(this) { it2 ->
if (!it2.value) {
HelperFunctions.showToast("Failed to get the list of items", this)
}
}.then
allLoading.add(itemListTransactionOver)
val sentEventIds = mutableListOf<String>()
// For all the requests, we get the event information as well as zone information so that we can display them
for (request in requests) {
if (request.eventId !in sentEventIds) {
sentEventIds.add(request.eventId)
val event = Observable<Event>()
val zone = Observable<Zone>()
// Create observables to be added in the list of all observable
val eventTransactionOver = Observable<Boolean>()
val zoneTransactionOver = Observable<Boolean>()
currentDatabase.eventDatabase.getEventFromId(request.eventId, event)
.observeOnce(this) {
if (it.value) {
// Get zone information
currentDatabase.zoneDatabase.getZoneInformation(
event.value!!.zoneId!!,
zone
).observeOnce(this) {
if (it.value) {
zoneNameFromEventId[event.value!!.eventId!!] =
zone.value!!.zoneName!!
}
}.then.updateOnce(this, zoneTransactionOver)
} else {
zoneTransactionOver.postValue(true, this)
}
}.then.updateOnce(this, eventTransactionOver)
allLoading.addAll(listOf(eventTransactionOver, zoneTransactionOver))
}
}
// Display a loading screen while the queries with the database are not over
HelperFunctions.showProgressDialog(this, allLoading, supportFragmentManager)
}
}.then
// Display a loading screen while the queries with the database are not over
HelperFunctions.showProgressDialog(
this,
listOf(matListTransactionOver),
supportFragmentManager
)
}
private val acceptMaterialRequest = { request: MaterialRequest ->
if (canAccept(request)) {
request.status = MaterialRequest.Status.ACCEPTED
val obs = ArrayList<Observable<Boolean>>()
obs.add(
currentDatabase.materialRequestDatabase.updateMaterialRequest(
request.requestId!!,
request
).observeOnce(this) {
if (!it.value) {
HelperFunctions.showToast("Failed to accept the request", this)
} else {
requests.set(
requests.indexOfFirst { it2 -> it2.requestId == request.requestId },
request,
this
)
}
}.then
)
for (item in request.items) {
val oldItem = items.first { it.first.itemId == item.key }
obs.add(
currentDatabase.itemDatabase.updateItem(
oldItem.first,
oldItem.second,
oldItem.third - item.value
)
)
}
// Display a loading screen while the queries with the database are not over
HelperFunctions.showProgressDialog(
this, obs, supportFragmentManager
)
} else {
HelperFunctions.showToast("Can not accept this request", this)
}
}
/**
* Checks if the material request can be accepted
*/
private fun canAccept(materialRequest: MaterialRequest): Boolean {
return materialRequest.status == MaterialRequest.Status.PENDING && materialRequest.items.all {
items.first { it2 -> it2.first.itemId == it.key }.third >= it.value
}
}
private val declineMaterialRequest = { request: MaterialRequest ->
createRefusalPopup(request)
}
@SuppressLint("InflateParams")
private fun createRefusalPopup(request: MaterialRequest) {
// Initialize a new layout inflater instance
val inflater: LayoutInflater =
getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
// Inflate a custom view using layout inflater
val view = inflater.inflate(R.layout.popup_refuse_request, null)
// Initialize a new instance of popup window
val popupWindow = PopupWindow(
view, // Custom view to show in popup window
LinearLayout.LayoutParams.MATCH_PARENT, // Width of popup window
LinearLayout.LayoutParams.WRAP_CONTENT // Window height
)
val slideIn = Slide()
slideIn.slideEdge = Gravity.TOP
popupWindow.enterTransition = slideIn
// Slide animation for popup window exit transition
val slideOut = Slide()
slideOut.slideEdge = Gravity.END
popupWindow.exitTransition = slideOut
// Get the widgets reference from custom view
val confirmButton = view.findViewById<Button>(R.id.id_btn_confirm_refuse_request)
val message = view.findViewById<TextView>(R.id.id_txt_refusal_explanation)
//set focus on the popup
popupWindow.isFocusable = true
// Set a click listener for popup's button widget
confirmButton.setOnClickListener {
request.status = MaterialRequest.Status.REFUSED
request.adminMessage = message.text.toString()
val updateEnded = Observable<Boolean>()
currentDatabase.materialRequestDatabase.updateMaterialRequest(
request.requestId!!,
request
).observeOnce(this) {
if (!it.value) {
HelperFunctions.showToast("Failed to decline the request", this)
} else {
requests.set(
requests.indexOfFirst { it2 -> it2.requestId == request.requestId },
request,
this
)
}
}.then.updateOnce(this, updateEnded)
// Display a loading screen while the queries with the database are not over
HelperFunctions.showProgressDialog(
this, listOf(
updateEnded
), supportFragmentManager
)
// Dismiss the popup window
popupWindow.dismiss()
}
// Finally, show the popup window on app
TransitionManager.beginDelayedTransition(this.recyclerView)
popupWindow.showAtLocation(this.recyclerView, Gravity.CENTER, 0, 0)
}
}