Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions PennMobile/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ dependencies {
// If you want the foundation layout, use the bundle or the specific activity compose you have defined
implementation libs.androidx.activity.compose
implementation libs.androidx.material3.android
implementation libs.places
// implementation libs.androidx.foundation.layout

androidTestImplementation libs.androidx.espresso.core
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ open class DiningHall : Parcelable {
var image: Int
private set

// key date string "yyyy-MM-dd"
// populated by DiningFragment.getMenusForWeek() for today + 6 days.
@Transient
val menusByDate: MutableMap<String, MutableList<Menu>> = HashMap()

@SerializedName("tblDayPart")
var menus: MutableList<Menu> = ArrayList()

Expand Down Expand Up @@ -55,6 +60,16 @@ open class DiningHall : Parcelable {
this.menus.sortedWith(comparator)
}

// Sort and store menus for a specific date in menusByDate.
fun sortMealsForDate(
date: String,
menus: MutableList<Menu>,
) {
val mealOrder = listOf("Breakfast", "Brunch", "Lunch", "Dinner", "Express")
val sorted = menus.sortedBy { mealOrder.indexOf(it.name) }
menusByDate[date] = sorted.toMutableList()
}

override fun describeContents(): Int = 0

override fun writeToParcel(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import dagger.hilt.android.AndroidEntryPoint
import rx.schedulers.Schedulers
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import kotlin.text.get

@AndroidEntryPoint
class DiningFragment : Fragment() {
Expand Down Expand Up @@ -293,36 +294,60 @@ class DiningFragment : Fragment() {
}

companion object {
// Gets the dining hall menus
fun getMenus(venues: MutableList<DiningHall>) {
try {
val idVenueMap = mutableMapOf<Int, DiningHall>()
venues.forEach { idVenueMap[it.id] = it }
val current = LocalDateTime.now()
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
val formatted = current.format(formatter)
val studentLife = MainActivity.studentLifeInstance
studentLife
.getMenus(formatted)
.subscribeOn(Schedulers.io())
.subscribe({ menus ->
menus?.filterNotNull()?.forEach { menu ->
menu.venue?.let { venue ->
idVenueMap[venue.venueId]?.let { diningHall ->
val diningHallMenus = diningHall.menus
diningHallMenus.add(menu)
diningHall.sortMeals(diningHallMenus)
private val dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")

// Fetch menus for today + next 6 days for all venues (closed and open)
fun getMenusForWeek(venues: MutableList<DiningHall>) {
val idVenueMap = mutableMapOf<Int, DiningHall>()
venues.forEach { idVenueMap[it.id] = it }

val today = LocalDateTime.now()
for (offset in 0..6) {
val date = today.plusDays(offset.toLong())
val formatted = date.format(dateFormatter)

try {
val studentLife = MainActivity.studentLifeInstance
studentLife
.getMenus(formatted)
.subscribeOn(Schedulers.io())
.subscribe({ menus ->
menus?.filterNotNull()?.forEach { menu ->
menu.venue?.let { venue ->
idVenueMap[venue.venueId]?.let { diningHall ->
synchronized(diningHall.menusByDate) {
val dayMenus =
diningHall.menusByDate
.getOrPut(formatted) { ArrayList() }
(dayMenus as java.util.ArrayList).add(menu)
diningHall.sortMealsForDate(formatted, dayMenus)
}
// Keep today's menus in the legacy .menus field so existing code that reads it still works
if (offset == 0) {
synchronized(diningHall) {
diningHall.sortMeals(
diningHall.menusByDate[formatted]
?: ArrayList(),
)
}
}
}
}
}
}
}, { throwable ->
Log.e("DiningFragment", "Error getting Menus", throwable)
})
} catch (e: Exception) {
e.printStackTrace()
}, { throwable ->
Log.e("DiningFragment", "Error getting menus for $formatted", throwable)
})
} catch (e: Exception) {
Log.e("DiningFragment", "Exception fetching menus for $formatted", e)
}
}
}

// single-day fetch
fun getMenus(venues: MutableList<DiningHall>) {
getMenusForWeek(venues)
}

// Takes a venue then adds an image and modifies venue name if name is too long
fun createHall(venue: Venue): DiningHall {
when (venue.id) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ import org.joda.time.format.DateTimeFormat
*/
class DiningInfoFragment : Fragment() {
private lateinit var menuParent: RelativeLayout
private var mDiningHall: DiningHall? = null
var mDiningHall: DiningHall? = null
private lateinit var mActivity: MainActivity

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mDiningHall = arguments?.getParcelable("DiningHall")
// mDiningHall = arguments?.getParcelable("DiningHall") // removed
mActivity = activity as MainActivity
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.util.Log
import androidx.core.content.edit
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.pennapps.labs.pennmobile.MainActivity
import com.pennapps.labs.pennmobile.compose.utils.Result
import com.pennapps.labs.pennmobile.compose.utils.SnackBarEvent
import com.pennapps.labs.pennmobile.dining.classes.DiningHall
Expand All @@ -16,9 +17,13 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import rx.schedulers.Schedulers
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import javax.inject.Inject

@HiltViewModel
Expand All @@ -40,18 +45,28 @@ class DiningViewModel
private val _snackBarEvent = MutableStateFlow<SnackBarEvent>(SnackBarEvent.None)
val snackBarEvent: StateFlow<SnackBarEvent> = _snackBarEvent

private val _menusByDate =
MutableStateFlow<Map<String, List<DiningHall.Menu>>>(emptyMap())
val menusByDate: StateFlow<Map<String, List<DiningHall.Menu>>> = _menusByDate

private val _favouriteDiningHalls =
diningRepo.favouriteDiningHalls.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(),
emptyList(),
)

val favouriteDiningHallIds: StateFlow<List<Int>> = _favouriteDiningHalls

val favouriteDiningHalls =
_favouriteDiningHalls
.map { favouriteIDs ->
allDiningHalls.value.filter { diningHall -> favouriteIDs.contains(diningHall.id) }
.combine(allDiningHalls) { favouriteIDs, halls ->
halls.filter { diningHall -> favouriteIDs.contains(diningHall.id) }
}
// when refreshed, wiped out the hearts in the all-dining-halls list
// .map { favouriteIDs ->
// allDiningHalls.value.filter { diningHall -> favouriteIDs.contains(diningHall.id) }
// }

init {
fetchSortOrder()
Expand Down Expand Up @@ -86,6 +101,42 @@ class DiningViewModel
}
}

fun fetchMenusForWeek(hall: DiningHall) {
_menusByDate.value = emptyMap()
val fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd")
val today = LocalDate.now()
val mealOrder = listOf("Breakfast", "Brunch", "Lunch", "Dinner", "Express")

for (offset in 0..6) {
val dateStr = today.plusDays(offset.toLong()).format(fmt)
try {
MainActivity.studentLifeInstance
.getMenus(dateStr)
.subscribeOn(Schedulers.io())
.subscribe({ menus ->
val dayMenus =
menus
?.filterNotNull()
?.filter { it.venue?.venueId == hall.id }
?.sortedWith { a, b ->
mealOrder.indexOf(a.name) - mealOrder.indexOf(b.name)
}
?: emptyList()

if (dayMenus.isNotEmpty()) {
_menusByDate.update { current ->
current + (dateStr to dayMenus)
}
}
}, { throwable ->
Log.e("DiningViewModel", "Error fetching menus for $dateStr", throwable)
})
} catch (e: Exception) {
Log.e("DiningViewModel", "Exception fetching menus for $dateStr", e)
}
}
}

private fun fetchSortOrder() {
_sortOrder.value =
DiningHallSortOrder.fromKey(
Expand Down
Loading
Loading