conventionschedule-android/app/src/main/java/com/adlerosn/brasilfurfest/schedule/fragments/ConventionSummaryFragment.kt

387 lines
19 KiB
Kotlin

package com.adlerosn.brasilfurfest.schedule.fragments
import android.app.AlertDialog
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.Space
import android.widget.TextView
import com.adlerosn.brasilfurfest.AssetImageViewerActivity
import com.adlerosn.brasilfurfest.CountdownActivity
import com.adlerosn.brasilfurfest.R
import com.adlerosn.brasilfurfest.helper.*
import com.adlerosn.brasilfurfest.helper.observables.Observable
import com.adlerosn.brasilfurfest.helper.observables.Observer
import com.adlerosn.brasilfurfest.schedule.EventActivity
import com.adlerosn.brasilfurfest.schedule.abstractDataTypes.dataholder.PeekableEvent
import com.adlerosn.brasilfurfest.schedule.abstractDataTypes.managed.Actions
import com.adlerosn.brasilfurfest.schedule.abstractDataTypes.managed.AttendeeConFavorite
import com.adlerosn.brasilfurfest.schedule.managers.ScheduleManagerGetter
import kotlinx.android.synthetic.main.activity_schedule.*
import kotlinx.android.synthetic.main.dialogview_schedule_registration_tier.view.*
import kotlinx.android.synthetic.main.dialogview_schedule_registration_tiers.view.*
import kotlinx.android.synthetic.main.fragment_schedule_summary.view.*
import kotlinx.android.synthetic.main.fragment_schedule_summary_countdown.view.*
import kotlinx.android.synthetic.main.fragment_schedule_summary_eventitem.view.*
import kotlinx.android.synthetic.main.fragment_schedule_summary_r621violation.view.*
import org.jetbrains.anko.doAsync
import org.jetbrains.anko.uiThread
import java.io.PrintWriter
import java.io.StringWriter
import java.text.SimpleDateFormat
import java.util.*
import kotlin.math.floor
import kotlin.math.roundToInt
class ConventionSummaryFragment : Fragment(), Observer<Observable<Any?>, Any?> {
companion object {
fun newInstance(): Fragment {
return ConventionSummaryFragment().apply {
arguments = Bundle()
}
}
}
override fun update(observable: Observable<Any?>, args: Any?) {
try {
safeActivity.runOnUiThread {
updateView()
}
} catch (e: Throwable) {
val writer = StringWriter()
e.printStackTrace(PrintWriter(writer))
val s = writer.toString()
Log.e(ConventionSummaryFragment::class.java.simpleName, s)
}
}
val safeActivity = ActivitiesForFragments["ScheduleActivity"]!!
val scheduleManager = ScheduleManagerGetter[safeActivity]
lateinit var rootView: View
lateinit var timer: Timer
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
rootView = inflater.inflate(R.layout.fragment_schedule_summary, container, false)
updateView()
timer = Timer()
timer.scheduleAtFixedRate(object : TimerTask() {
override fun run() { safeActivity.runOnUiThread {
try {
rootView.let {
this@ConventionSummaryFragment.updateView()
}
} catch (e: Throwable){
val writer = StringWriter()
e.printStackTrace(PrintWriter(writer))
val s = writer.toString()
Log.e(ConventionSummaryFragment::class.java.simpleName, s)
}
} }
}, 3000, 30*1000)
scheduleManager.addObserver(this)
return rootView
}
private fun updateView() {
safeActivity.runOnUiThread {
val conventionTime = scheduleManager.conventionTime
val context = rootView.context
val inflater = context.layoutInflater
rootView.textRegistrationTier.text = scheduleManager.attendeeFavorites.registrationTier.names.solved
rootView.textRegistrationBenefits.text = scheduleManager.attendeeFavorites.registrationTier.benefits.size.run { pluralize(
R.string.schedule_tierbenefit_none.getString(),
R.string.schedule_tierbenefit_singular.getString().format(this),
R.string.schedule_tierbenefit_plural.getString().format(this)
) }
rootView.registrationTierSection.setOnClickListener {
val dialog = AlertDialog.Builder(safeActivity).create()
dialog.setTitle(R.string.schedule_registrationtier_question.getString())
val scroller = inflater.inflate(R.layout.dialogview_schedule_registration_tiers)
scheduleManager.convention.registrationTiers.sortedBy { it.level }.forEach {
scroller.container.addView(inflater.inflate(R.layout.dialogview_schedule_registration_tier).apply {
tier.text = it.names.solved
it.benefits.forEach {
benefitsList.addView(TextView(context).apply {
this.text = it.solved
this.setTextColor(scroller.context.getColorCompat(R.color.colorBase05))
})
}
if (it.benefits.isEmpty()) ticket.visibility = View.GONE
setOnClickListener { _ ->
dialog.dismiss()
scheduleManager.attendeeFavorites.registrationTier = it
}
})
}
dialog.setView(scroller)
dialog.setButton(AlertDialog.BUTTON_NEUTRAL, R.string.dialog_cancel.getString()) { dialogInterface: DialogInterface, _: Int -> dialogInterface.dismiss() }
val callbacks =
(scheduleManager.convention.registrationLinks.filter { scheduleManager.conventionTime in it.lifetime } + listOf(null, null))
.subList(0, 2).let {
Pair(it.getOrNull(0), it.getOrNull(1))
}.let {
listOf(
Pair(it.first, AlertDialog.BUTTON_POSITIVE),
Pair(it.second, AlertDialog.BUTTON_NEGATIVE)
)
}.map {
it.first?.run {
dialog.setButton(it.second, name.solved) { dialogInterface: DialogInterface, _: Int ->
val i = Intent(Intent.ACTION_VIEW)
i.data = Uri.parse(url.solved)
dialog.context.startActivity(i)
dialogInterface.dismiss()
}
fun(){
this.color?.let { color -> dialog.getButton(it.second).setTextColor(color) }
}
}
}
dialog.setOnShowListener { callbacks.filterNotNull().forEach { it() } }
dialog.show()
}
if (!scheduleManager.attendeeFavorites.registrationTierSelectorShown) {
rootView.registrationTierSection.performClick()
scheduleManager.attendeeFavorites.registrationTierSelectorShown = true
}
val mapButtons = rootView.mapButtons
mapButtons.removeAllViews()
val maps = scheduleManager.convention.maps
maps.withIndex().forEach {
val isLast = it.index+1 >= maps.size
Button(rootView.context).apply {
text = it.value.name.solved
setOnClickListener {view ->
Intent(view.context, AssetImageViewerActivity::class.java).apply {
putExtra("asset", it.value.image.solved)
startActivity(this)
}
}
setTextColor(mapButtons.context.getColorCompat(R.color.colorBase04).asColorStateList)
backgroundTintList = mapButtons.context.getColorCompat(R.color.colorBase18).asColorStateList
mapButtons.addView(this)
}
if(!isLast){
Space(rootView.context).apply {
minimumWidth = 4.asDpToPx.roundToInt()
minimumHeight = 0
mapButtons.addView(this)
}
}
}
val eventCountdown = scheduleManager.nextEditionStartCountdown
if (eventCountdown == null)
rootView.countdown.visibility = View.GONE
else {
rootView.countdown.visibility = View.VISIBLE
rootView.countdownTitle.text = context
.getString(R.string.thingsLacking_to)
.format(
eventCountdown.let { (f, s, t) ->
"%dd %dh %dm".format(f, s, t)
}
)
}
rootView.countdown.setOnClickListener {
Intent(safeActivity, CountdownActivity::class.java).let {
it.putExtra("label", scheduleManager.convention.genericName)
it.putExtra("counter", scheduleManager.nextEditionStartTime)
startActivity(it)
}
}
val allHappening = scheduleManager.convention.events
.filterNot {
it.isCustom
}.map {
AttendeeConFavorite(scheduleManager.convention, it)
} +
scheduleManager.attendeeFavorites.toList().filter {
it.isCustom
}
val happeningNow = allHappening
.filter { conventionTime in it.timeRange }
.sortedBy { -it.timeRange.start.timeInMillis }
val nextDayPart = allHappening
.sortedBy {
it.timeRange.start.timeInMillis
}
.firstOrNull {
it.timeRange.start.timeInMillis > conventionTime.timeInMillis
}
?.timeRange
?.start
?.dayRange
?.split(scheduleManager.convention.splitDayIn)
?.dropWhile {
it.start.timeInMillis <= conventionTime.timeInMillis
}
?.getOrNull(0)
val happeningNext = nextDayPart?.let { part ->
allHappening.filter {
it.timeRange.start in part
}
} ?: listOf()
rootView.eventsNowDescription.text = happeningNow.size.run { pluralize(
R.string.schedule_now_no_event.getString(),
R.string.schedule_now_n_event.getString().format(this),
R.string.schedule_now_n_events.getString().format(this)
) }
rootView.eventsComingDescription.text = happeningNext.size.run { pluralize(
R.string.schedule_coming_no_event.getString(),
R.string.schedule_coming_n_event.getString().format(this),
R.string.schedule_coming_n_events.getString().format(this)
) }
rootView.eventsNowContainer.removeAllViews()
rootView.eventsComingContainer.removeAllViews()
happeningNow.forEach { rootView.eventsNowContainer.addView(renderEventCard(context, it)) }
happeningNext.forEach { rootView.eventsComingContainer.addView(renderEventCard(context, it)) }
rootView.r621watcher.removeAllViews()
if (scheduleManager.convention.r621checker) {
val favorites = scheduleManager.attendeeFavorites.toList()
val r621watchedDays =
scheduleManager.convention.days.map {
it.dayRange
}.filter {
it.start.timeInMillis > scheduleManager.convention.startCalendarOn.timeInMillis
}
r621watchedDays.forEach { dayRange ->
val todayFavorites = favorites.filter { it.timeRange.start in dayRange }
val sleepFavorites = todayFavorites.filter { it.kind == Actions.Intention.SLEEP }.filterNot { sleep ->
todayFavorites.filter { sleep.timeRange in it.timeRange }.size > 1
}
val eatFavorites = todayFavorites.filter { it.kind == Actions.Intention.EAT }
val showerFavorites = todayFavorites.filter { it.kind == Actions.Intention.SHOWER }
val daySegment = 24.0 / scheduleManager.convention.splitDayIn
if (
((sleepFavorites.size * daySegment) < 6)
or
((eatFavorites.size * daySegment) < 2)
or
((showerFavorites.size * daySegment) < 1)
) {
rootView.r621watcher.addView(
rule621renderer(
context,
dayRange.start,
sleepFavorites.size * daySegment,
eatFavorites.size * daySegment,
showerFavorites.size * daySegment
)
)
}
}
}
val hashtag = scheduleManager.convention.hashtagReminder
if (hashtag == null) {
rootView.shareReminder.visibility = View.GONE
} else {
rootView.shareReminderTitle.text = hashtag
}
rootView.readTheRules.setOnClickListener {
safeActivity.container.currentItem = scheduleManager.convention.days.size+1
}
}
}
private fun dowFormatter(context: Context) = SimpleDateFormat("E", context.runtimeLanguage.locale)
private fun hourMinuteFormatter(context: Context) = SimpleDateFormat("HH:mm", context.runtimeLanguage.locale)
private fun renderEventCard(context: Context, attendeeConFavorite: AttendeeConFavorite): View{
val view = context.layoutInflater.inflate(R.layout.fragment_schedule_summary_eventitem)
val event = attendeeConFavorite.findInConvention(scheduleManager.convention)
view.startDay.text = dowFormatter(context).format(attendeeConFavorite.timeRange.start.timeInMillis).capitalize()
view.startText.text = hourMinuteFormatter(context).format(attendeeConFavorite.timeRange.start.timeInMillis)
view.finishText.text = hourMinuteFormatter(context).format(attendeeConFavorite.timeRange.finish.timeInMillis)
view.eventTitle.text = attendeeConFavorite.getString()
view.eventSubtitle.text = attendeeConFavorite.getSecondaryString()
if(attendeeConFavorite in scheduleManager.attendeeFavorites) {
view.starButton.setOnClickListener {
val dialog = AlertDialog.Builder(safeActivity).create()
dialog.setTitle(context.getString(R.string.schedule_action_interest_remove))
dialog.setButton(AlertDialog.BUTTON_NEUTRAL, context.getString(R.string.dialog_cancel)) { dialogInterface, _ ->
dialogInterface.dismiss()
}
dialog.setButton(AlertDialog.BUTTON_NEGATIVE, context.getString(R.string.list_action_remove)) { dialogInterface, _ ->
dialogInterface.dismiss()
scheduleManager.attendeeFavorites.remove(attendeeConFavorite)
updateView()
}
dialog.show()
}
} else {
view.star.setImageResource(R.drawable.ic_star_border_black_24dp)
view.starButton.setOnClickListener {
view.star.setImageResource(R.drawable.ic_star_half_black_24dp)
scheduleManager.attendeeFavorites.add(attendeeConFavorite)
updateView()
}
}
if (event != null) {
if (
event.hiddenFromTimeTable
or
(scheduleManager.attendeeFavorites.registrationTier.level !in event.attendableBy.map { it.level })
){
view.star.visibility = View.INVISIBLE
view.starButton.setOnClickListener { }
}
}
if (event?.language == null) {
view.flag.visibility = View.GONE
} else {
view.flag.setImageResource(event.language.drawableId)
}
view.setOnClickListener {
context.startActivity(
Intent(safeActivity, EventActivity::class.java).apply {
putExtra("favorite", attendeeConFavorite)
putExtra("offerStar", true)
}
)
}
bindPeekAndPop(
safeActivity,
view as ViewGroup,
view,
if (view.star.visibility == View.INVISIBLE)
null
else
attendeeConFavorite in scheduleManager.attendeeFavorites,
{ doAsync { uiThread { view.starButton.callOnClick() } } },
{ doAsync { uiThread { view.callOnClick() } } },
scheduleManager.convention.events.firstOrNull {
it.conbookId == attendeeConFavorite.conBookId
}?.let { PeekableEvent(it) }
?: PeekableEvent(attendeeConFavorite)
)
return view
}
private fun rule621renderer(context: Context, day: GregorianCalendar, sleep: Double, meals: Double, showers: Double): View{
val view = context.layoutInflater.inflate(R.layout.fragment_schedule_summary_r621violation)
view.r621Description.text = context.getString(R.string.on_something).format(
SimpleDateFormat("EEEE (d)", context.runtimeLanguage.locale).format(day.timeInMillis)
)
view.r621_sleep_minimum.text = context.getString(R.string.r621_minimum_is_d).format(6)
view.r621_eat_minimum.text = context.getString(R.string.r621_minimum_is_d).format(2)
view.r621_shower_minimum.text = context.getString(R.string.r621_minimum_is_d).format(1)
view.r621_sleep_found.text = context.getString(R.string.r621_found_d).format(floor(sleep).roundToInt())
view.r621_eat_found.text = context.getString(R.string.r621_found_d).format(floor(meals).roundToInt())
view.r621_shower_found.text = context.getString(R.string.r621_found_d).format(floor(showers).roundToInt())
if(sleep<6) view.r621_sleep_found.setTextColor(context.getColorCompat(R.color.colorBase06))
if(meals<2) view.r621_eat_found.setTextColor(context.getColorCompat(R.color.colorBase06))
if(showers<1) view.r621_shower_found.setTextColor(context.getColorCompat(R.color.colorBase06))
return view
}
}