Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dining redesign: open until subtitle, updated day chips, availability card redesign, improved chart and menus #48

Merged
merged 33 commits into from
Aug 15, 2020
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
2098eda
added date to day chips by making chips into radiobuttons
kaushikravikumar May 9, 2020
4c66c5c
removed lite_lunch logic, since its grouped with lunch in dining menu…
kaushikravikumar May 9, 2020
fc468a5
made toolbar include subtitle with openclose info
kaushikravikumar Jun 14, 2020
2b478a0
moved parseTime function to fluxutil
kaushikravikumar Jun 14, 2020
f4960d4
added next day to facilityhours endpoint
kaushikravikumar Jun 14, 2020
3805277
removed duplicate operating hours request
kaushikravikumar Jun 19, 2020
5dd527f
created two separate variables to store operating hours: one for chec…
kaushikravikumar Jun 21, 2020
c4e3857
added curr date textview
kaushikravikumar Jun 21, 2020
dd50c58
changed so open/closed text only colors red or green for open or clos…
kaushikravikumar Jun 21, 2020
9c6779a
removed extra line
kaushikravikumar Jun 21, 2020
9c0698d
Bump Gradle, package versions
kungpaogao Jun 26, 2020
5243351
Implement dynamic chips (shows today first)
kungpaogao Jun 26, 2020
e658a89
Remove unnecessary outline
kungpaogao Jun 26, 2020
47758a5
Format code
kungpaogao Jun 27, 2020
989e567
Implement basic layout for new availability card
kungpaogao Jun 27, 2020
7cdbde8
Availability number now updates according to crowdedness
kungpaogao Jun 27, 2020
9753081
Availability card displays live max capacity
kungpaogao Jun 27, 2020
154c8b3
made all dates yyyy-mm-dd
kaushikravikumar Jun 27, 2020
658abd4
fixed double loading of historical chart bug
kaushikravikumar Jun 27, 2020
a2fe498
Move section headers outside of card
kungpaogao Jun 27, 2020
aa9fa53
Merge branch 'dining_redesign' of https://github.com/cornell-dti/camp…
kungpaogao Jun 27, 2020
450baef
Implement color changes for availability card
kungpaogao Jun 27, 2020
25ac06b
Update green/teal color
kungpaogao Jul 5, 2020
e2b6ba0
Update menu UI to match design mockups
kungpaogao Jul 5, 2020
ee75f8d
added last updated text
kaushikravikumar Jul 5, 2020
a9af916
merge branch 'dining_redesign' of https://github.com/cornell-dti/camp…
kaushikravikumar Jul 5, 2020
ab97968
changed color of is it accurate text
kaushikravikumar Jul 5, 2020
ab79278
fixed spacing between last updated text and next component below and …
kaushikravikumar Jul 5, 2020
8a44223
Fix operating hours not displaying on Android
kungpaogao Jul 11, 2020
9223977
Update spacing for operating hours in historical data card
kungpaogao Jul 11, 2020
42c532f
Merge remote-tracking branch 'origin/dining_redesign' into dining_red…
kungpaogao Jul 11, 2020
995f337
Fix layout scaling for date selection buttons
kungpaogao Jul 11, 2020
975977e
Implement graying out of chart + other chart improvements
kungpaogao Jul 11, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ data class MenuClass(
val breakfastItems: List<MenuItem>,
val brunchItems: List<MenuItem>,
val lunchItems: List<MenuItem>,
val liteLunchItems: List<MenuItem>,
val dinnerItems: List<MenuItem>
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package org.cornelldti.density.density.facilitydetail
import android.graphics.Color
import android.os.Bundle
import android.text.format.DateFormat
import android.text.format.DateUtils
import android.text.method.LinkMovementMethod
import android.util.Log
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.text.HtmlCompat
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
Expand All @@ -25,8 +27,11 @@ import org.cornelldti.density.density.colorbarutil.ColorBarDataSet
import org.cornelldti.density.density.colorbarutil.ColorBarMarkerView
import org.cornelldti.density.density.data.FacilityClass
import org.cornelldti.density.density.data.MenuClass
import org.cornelldti.density.density.network.JsonParser
import org.cornelldti.density.density.util.FluxUtil
import org.cornelldti.density.density.util.ValueFormatter
import java.util.*
import kotlin.collections.ArrayList

class FacilityInfoPage : BaseActivity() {

Expand All @@ -43,7 +48,8 @@ class FacilityInfoPage : BaseActivity() {
private var wasCheckedDay: Int = -1
private var wasCheckedMenu: Int = -1

private var opHours: List<String> = ArrayList() // KEEPS TRACK OF OPERATING HOURS FOR FACILITY
private var opHoursStrings: List<String> = ArrayList() // KEEPS TRACK OF OPERATING HOURS STRINGS FOR FACILITY
private var opHoursTimestamps: List<Pair<Long, Long>> = ArrayList() // KEEPS TRACK OF OPERATING HOURS TIME STAMPS FOR FACILITY
private var densities: List<Double> = ArrayList() // KEEPS TRACK OF HISTORICAL DENSITIES

public override fun onCreate(savedInstanceState: Bundle?) {
Expand Down Expand Up @@ -92,6 +98,9 @@ class FacilityInfoPage : BaseActivity() {
wasCheckedDay = checkedId
selectedDay = day
fetchHistoricalJSON(day, facilityClass!!.id)
val daysDifference = FluxUtil.getDayDifference(FluxUtil.dayString, selectedDay!!)
updateOperatingHoursOfSelectedDay(FluxUtil.getDateStringDaysAfter(daysDifference, false))
setOperatingHours(selectedDay!!)
}
}

Expand All @@ -108,7 +117,7 @@ class FacilityInfoPage : BaseActivity() {
-1 -> FluxUtil.dayString
}
val daysDifference = FluxUtil.getDayDifference(FluxUtil.dayString, selectedDay)
fetchMenuJSON(day = FluxUtil.getDateDaysAfter(daysDifference), facilityId = facilityClass!!.id)
fetchMenuJSON(day = FluxUtil.getDateStringDaysAfter(daysDifference, true), facilityId = facilityClass!!.id)
}

private fun setupBarChart() {
Expand Down Expand Up @@ -198,6 +207,82 @@ class FacilityInfoPage : BaseActivity() {

}

private fun fetchOperatingHours(date: Date) {
val c = Calendar.getInstance()
c.time = date
c.add(Calendar.DATE, 1)
val nextDay: Date = c.time
api.facilityHours(facilityId=facilityClass!!.id, startDate = FluxUtil.convertDateObjectToString(date),
endDate = FluxUtil.convertDateObjectToString(nextDay),
facilityHoursTimeStampsOnResponse = {
hoursTimeStampsList ->
opHoursTimestamps = hoursTimeStampsList
},
facilityHoursStringsOnResponse = {
hoursStringsList ->
opHoursStrings = hoursStringsList
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will things get messed up if opHoursStrings is not set in time for the UI updates?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it won't throw an error since it's just an empty list...

}

/**
* updateOperatingHoursOfSelectedDay() is meant to only update the facility hours under the historical data chart
* for the selected day, and does not affect the facility hours used to check if the place is open. Thus, here
* facilityHoursTimeStampsOnResponse is not defined.
*/
private fun updateOperatingHoursOfSelectedDay(date: String) {
api.facilityHours(facilityId=facilityClass!!.id, startDate = date,
endDate = date,
facilityHoursTimeStampsOnResponse = {
// Isn't Defined!
},
facilityHoursStringsOnResponse = {
hoursStringsList ->
opHoursStrings = hoursStringsList
})
}

private fun checkFacilityIsOpen() {
var isOpen: Boolean = false
var openUntil: Long = -1
var opensNext: Long = -1

val currentTime = System.currentTimeMillis() / 1000L
for(i in 0 until opHoursTimestamps.size - 1) {
// Current Time falls into one of the open time slots
if (currentTime >= opHoursTimestamps[i].first && currentTime < opHoursTimestamps[i].second) {
isOpen = true
openUntil = opHoursTimestamps[i].second
}
// Current Time before first time slot of day
else if (i == 0 && currentTime < opHoursTimestamps[i].first) {
opensNext = opHoursTimestamps[i].first
}
// Current Time is after the last time slot of day
else if(i == opHoursTimestamps.size - 2 && currentTime >= opHoursTimestamps[i].second) {
opensNext = opHoursTimestamps[opHoursTimestamps.size - 1].first
}
// Current Time is between two time slots in day
else if(i > 0 && currentTime >= opHoursTimestamps[i-1].second && currentTime < opHoursTimestamps[i].first) {
opensNext = opHoursTimestamps[i].first
}
}
if(opensNext == -1L && openUntil == -1L) {
topBar.setSubtitleTextColor(getResources().getColor(R.color.closed_facility))
topBar.subtitle = "Closed"
}
else {
if(isOpen) {
topBar.setSubtitleTextColor(getResources().getColor(R.color.open_facility))
topBar.subtitle = "Open" + " until " + FluxUtil.parseTime(openUntil)

}
else {
topBar.setSubtitleTextColor(getResources().getColor(R.color.closed_facility))
topBar.subtitle = "Closed" + " opens at " + FluxUtil.parseTime(opensNext)
}
}
}

private fun initializeView() {
topBar.title = facilityClass!!.name
currentOccupancy.text = getString(facilityClass!!.densityResId)
Expand All @@ -206,10 +291,24 @@ class FacilityInfoPage : BaseActivity() {
topBar.setNavigationOnClickListener { onBackPressed() }

setToday(FluxUtil.dayString)
setDayChipsDate()
setDayChipOnClickListener()
setPills()
}

private fun setDayChipsDate() {
val chipsList = listOf(sun, mon, tue, wed, thu, fri, sat)
val dayStrings = listOf(getString(R.string.SUN), getString(R.string.MON), getString(R.string.TUE), getString(R.string.WED),
getString(R.string.THU), getString(R.string.FRI), getString(R.string.SAT))
for (i in 0..6) {
val daysDifference = FluxUtil.getDayDifference(FluxUtil.dayString, dayStrings.get(i))
val date = FluxUtil.getDateDaysAfter(daysDifference)
val chip = chipsList.get(i)
chip.text = HtmlCompat.fromHtml(chip.text.toString() + "<br>" + "<br>" +
"<b>" + date.date + "</b>", HtmlCompat.FROM_HTML_MODE_LEGACY)
}
}

private fun setPills() {
val bars = ArrayList<ImageView?>()
bars.add(firstPill)
Expand All @@ -230,7 +329,6 @@ class FacilityInfoPage : BaseActivity() {
for (i in 0..facilityClass!!.occupancyRating) {
bars[i]?.setColorFilter(ContextCompat.getColor(applicationContext, color))
}

}

/**
Expand All @@ -249,24 +347,27 @@ class FacilityInfoPage : BaseActivity() {
getString(R.string.FRI) -> fri.isChecked = true
getString(R.string.SAT) -> sat.isChecked = true
}
wasCheckedDay = dayChips.checkedChipId
wasCheckedDay = dayChips.checkedRadioButtonId
}

private fun setOperatingHours(day: String) {
Log.d("SET", "OPERATING")
val hourTitle = FluxUtil.dayFullString(day)
todayHours.text = hourTitle
facilityHours.text = ""
for (operatingSegment in opHours) {
val allHours = facilityHours.text.toString() + operatingSegment + if (opHours.indexOf(operatingSegment) == opHours.size - 1) "" else "\n"
for (operatingSegment in opHoursStrings) {
val allHours = facilityHours.text.toString() + operatingSegment + if (opHoursStrings.indexOf(operatingSegment) == opHoursStrings.size - 1) "" else "\n"
facilityHours.text = allHours
}
}

override fun updateUI() {
Log.d("updatedFPUI", "updating")
fetchOperatingHours(date=FluxUtil.getDateObject(selectedDay!!))
checkFacilityIsOpen()
setOperatingHours(day=selectedDay!!)
fetchHistoricalJSON(day = selectedDay!!, facilityId = facilityClass!!.id)
fetchMenuJSON(day = FluxUtil.getCurrentDate(), facilityId = facilityClass!!.id)
fetchMenuJSON(day = FluxUtil.getCurrentDate(yearBeginning = true), facilityId = facilityClass!!.id)
}

private fun fetchHistoricalJSON(day: String, facilityId: String) {
Expand All @@ -276,10 +377,6 @@ class FacilityInfoPage : BaseActivity() {
fetchHistoricalJSONOnResponse = { historicalDensities ->
densities = historicalDensities
setupBarChart()
},
fetchOperatingHoursOnResponse = { operatingHours ->
opHours = operatingHours
setOperatingHours(day)
}
)
}
Expand All @@ -292,16 +389,14 @@ class FacilityInfoPage : BaseActivity() {
if (menu?.breakfastItems?.size == 0
&& menu.brunchItems.isEmpty()
&& menu.lunchItems.isEmpty()
&& menu.liteLunchItems.isEmpty()
&& menu.dinnerItems.isEmpty()) {
menuCard.isGone = true
} else {
menuCard.isVisible = true
breakfast.isVisible = menu?.breakfastItems?.isNotEmpty() ?: false
brunch.isVisible = menu?.brunchItems?.isNotEmpty() ?: false
lunch.isVisible = menu?.lunchItems?.isNotEmpty() ?: false
lite_lunch.isVisible = menu?.liteLunchItems?.isNotEmpty() ?: false
dinner.isVisible = menu?.dinnerItems?.isNotEmpty() ?: false
breakfast.isGone = !(menu?.breakfastItems?.isNotEmpty() ?: false)
brunch.isGone = !(menu?.brunchItems?.isNotEmpty() ?: false)
lunch.isGone = !(menu?.lunchItems?.isNotEmpty() ?: false)
dinner.isGone = !(menu?.dinnerItems?.isNotEmpty() ?: false)
wasCheckedMenu = firstVisibleChipId(menu)
showMenu(menu, wasCheckedMenu)
menuChips.setOnCheckedChangeListener { _, checkedId -> showMenu(menu, checkedId) }
Expand All @@ -327,10 +422,6 @@ class FacilityInfoPage : BaseActivity() {
lunch.isChecked = true
return R.id.lunch
}
menu.liteLunchItems.isNotEmpty() -> {
lite_lunch.isChecked = true
return R.id.lite_lunch
}
menu.dinnerItems.isNotEmpty() -> {
dinner.isChecked = true
return R.id.dinner
Expand All @@ -352,7 +443,6 @@ class FacilityInfoPage : BaseActivity() {
R.id.breakfast -> menuItemListViewAdapter = MenuListAdapter(menu.breakfastItems, this)
R.id.brunch -> menuItemListViewAdapter = MenuListAdapter(menu.brunchItems, this)
R.id.lunch -> menuItemListViewAdapter = MenuListAdapter(menu.lunchItems, this)
R.id.lite_lunch -> menuItemListViewAdapter = MenuListAdapter(menu.liteLunchItems, this)
R.id.dinner -> menuItemListViewAdapter = MenuListAdapter(menu.dinnerItems, this)
-1 -> if (wasCheckedMenu != -1) menuChips.check(wasCheckedMenu)
else menuItemListViewAdapter = MenuListAdapter(ArrayList(), this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,24 +118,15 @@ class API(context: Context) {
fun fetchHistoricalJSON(
day: String,
facilityId: String,
fetchOperatingHoursOnResponse: (operatingHours: List<String>) -> Unit,
fetchHistoricalJSONOnResponse: (densities: List<Double>) -> Unit
) {
val operatingHoursRequest = getRequest(
url = "$OPERATING_HOURS_ENDPOINT?id=$facilityId&startDate=${FluxUtil.getDate(day)}&endDate=${FluxUtil.getDate(day)}",
onResponse = { response ->
fetchOperatingHoursOnResponse(JsonParser.parseOperatingHours(response))
},
onError = { error -> Log.d("ERROR MESSAGE", error.toString()) }
)
val historicalDataRequest = getRequest(
url = "$HISTORICAL_DATA_ENDPOINT?id=$facilityId",
onResponse = { response ->
fetchHistoricalJSONOnResponse(JsonParser.parseHistorical(response, day))
},
onError = { error -> Log.d("ERROR MESSAGE", error.toString()) }
)
queue.add(operatingHoursRequest)
queue.add(historicalDataRequest)
}

Expand Down Expand Up @@ -173,6 +164,21 @@ class API(context: Context) {
queue.add(menuRequest)
}

fun facilityHours(facilityId: String, startDate: String, endDate: String, facilityHoursTimeStampsOnResponse: (List<Pair<Long, Long>>) -> Unit,
facilityHoursStringsOnResponse: (List<String>) -> Unit) {
val facilityHoursRequest = getRequest(
url = "$OPERATING_HOURS_ENDPOINT?id=$facilityId&startDate=$startDate&endDate=$endDate",
onResponse = { response ->
facilityHoursTimeStampsOnResponse(JsonParser.parseOperatingHoursToTimestampList(response))
facilityHoursStringsOnResponse(JsonParser.parseOperatingHours(response))
},
onError = {
error -> Log.d("Error fetching hours", error.networkResponse.toString());
}
)
queue.add(facilityHoursRequest)
}

private fun getRequest(
url: String,
onResponse: (jsonArray: JSONArray) -> Unit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package org.cornelldti.density.density.network
import android.text.format.DateFormat
import org.cornelldti.density.density.DensityApplication
import org.cornelldti.density.density.data.*
import org.cornelldti.density.density.util.FluxUtil
import org.json.JSONArray
import org.json.JSONException
import java.text.SimpleDateFormat
Expand Down Expand Up @@ -62,7 +63,6 @@ object JsonParser {
breakfastItems = breakfast,
brunchItems = brunch,
lunchItems = lunch,
liteLunchItems = liteLunch,
dinnerItems = dinner
)
} catch (e: JSONException) {
Expand Down Expand Up @@ -95,14 +95,36 @@ object JsonParser {
val segment = hours.getJSONObject(i).getJSONObject("dailyHours")
val start = segment.getLong("startTimestamp")
val end = segment.getLong("endTimestamp")
operatingHours.add(parseTime(start) + " – " + parseTime(end))
operatingHours.add(FluxUtil.parseTime(start) + " – " + FluxUtil.parseTime(end))
}
} catch (e: JSONException) {
e.printStackTrace()
}
return operatingHours
}

fun parseOperatingHoursToTimestampList(jsonArray: JSONArray): List<Pair<Long, Long>> {
val operatingHours = arrayListOf<Pair<Long, Long>>()
try {
val hours = jsonArray.getJSONObject(0).getJSONArray("hours")
for (i in 0 until hours.length()) {
val segment = hours.getJSONObject(i).getJSONObject("dailyHours")
val start = segment.getLong("startTimestamp")
val end = segment.getLong("endTimestamp")
operatingHours.add(Pair(start, end))
}
val nextDayHours = jsonArray.getJSONObject(1).getJSONArray("hours")
val nextDaySegment = nextDayHours.getJSONObject(0).getJSONObject("dailyHours")
val nextDaySlotStart = nextDaySegment.getLong("startTimestamp")
val nextDaySlotEnd = nextDaySegment.getLong("endTimestamp")
operatingHours.add(Pair(nextDaySlotStart, nextDaySlotEnd))

} catch (e: JSONException) {
e.printStackTrace()
}
return operatingHours
}

fun parseHistorical(jsonArray: JSONArray, day: String): List<Double> {
val densities = arrayListOf<Double>()
try {
Expand All @@ -116,15 +138,4 @@ object JsonParser {
}
return densities
}

private fun parseTime(timestamp: Long): String {
val timeZone = Calendar.getInstance().timeZone
var format = SimpleDateFormat("h:mma", Locale.US)
if (DateFormat.is24HourFormat(DensityApplication.getAppContext())) {
format = SimpleDateFormat("HH:mm", Locale.US)
}
format.timeZone = timeZone

return format.format(Date(timestamp * 1000)).toLowerCase(Locale.US)
}
}
Loading