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, Any?> { companion object { fun newInstance(): Fragment { return ConventionSummaryFragment().apply { arguments = Bundle() } } } override fun update(observable: Observable, 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 } }