Skip to content

Commit

Permalink
Fix some loading errors, add more proper handling for hob line
Browse files Browse the repository at this point in the history
  • Loading branch information
steviek committed Jan 31, 2025
1 parent b3b6e98 commit 5c6e97a
Show file tree
Hide file tree
Showing 23 changed files with 286 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ object PathRepository {
private val mutex = Mutex()

fun getResults(now: Instant, staleness: Staleness): FetchWithPrevious<PathServiceResults> {
Logging.d("getResults, staleAfter: ${staleness.staleAfter}, invalidAfter: ${staleness.invalidAfter}")
val previous = getCachedResults(now)
return FetchWithPrevious.create(
previous = previous,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ data class TempLineInfo(
val fallback get() = TempLineInfo(
displayName = "33rd Street ⇆ World Trade Center",
codes = listOf("WTC-33", "33-WTC"),
lightColor = "782C94",
lightColor = "65C100",
darkColor = null,
)
}
Expand Down
4 changes: 2 additions & 2 deletions composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ android {
applicationId = "com.sixbynine.transit.path"
minSdk = libs.versions.android.minSdk.get().toInt()
targetSdk = libs.versions.android.targetSdk.get().toInt()
versionCode = 58
versionName = "3.6.3"
versionCode = 60
versionName = "3.6.5"
resourceConfigurations += setOf("en", "es")
}
buildFeatures {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.sixbynine.transit.path

import com.google.firebase.Firebase
import com.google.firebase.crashlytics.crashlytics
import com.sixbynine.transit.path.analytics.Analytics
import com.sixbynine.transit.path.app.ui.ActivityRegistry
import com.sixbynine.transit.path.native.NativeHolder
Expand All @@ -24,7 +26,8 @@ class MobilePathApplication : PathApplication() {
WidgetRefreshWorker.scheduleOneTime()
}
}
}
},
Firebase.crashlytics::recordException
)

ActivityRegistry.register(this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ actual fun exportDevLogs(logs: List<LogRecord>) {
writer.write("timestamp\tlevel\tmessage")
writer.newLine()

logs.forEach { log ->
logs.asReversed().forEach { log ->
writer.write(log.timestamp.toLocalDateTime(NewYorkTimeZone).toString())
writer.write("\t")
writer.write(log.level.toString())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.nanoseconds
import kotlin.time.Duration.Companion.seconds

object AndroidLocationProvider : LocationProvider {

Expand All @@ -52,7 +52,7 @@ object AndroidLocationProvider : LocationProvider {
override val locationPermissionResults: SharedFlow<LocationPermissionRequestResult> =
_locationPermissionResultsChannel.receiveAsFlow().shareIn(GlobalScope, WhileSubscribed())

override val defaultLocationCheckTimeout = 700.seconds
override val defaultLocationCheckTimeout = 700.milliseconds

override fun hasLocationPermission(): Boolean {
if (VERSION.SDK_INT < 23 || !isLocationSupportedByDevice) return false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.sixbynine.transit.path.widget

import android.annotation.SuppressLint
import android.content.Context
import com.sixbynine.transit.path.Logging
import com.sixbynine.transit.path.MobilePathApplication
import com.sixbynine.transit.path.api.Line
import com.sixbynine.transit.path.api.StationSort.Alphabetical
Expand All @@ -12,6 +13,7 @@ import com.sixbynine.transit.path.util.DataResult
import com.sixbynine.transit.path.util.FetchWithPrevious
import com.sixbynine.transit.path.util.Staleness
import com.sixbynine.transit.path.util.isFailure
import com.sixbynine.transit.path.util.isSuccess
import com.sixbynine.transit.path.widget.configuration.WidgetConfigurationManager
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
Expand All @@ -30,6 +32,8 @@ object AndroidWidgetDataRepository {
private const val HasErrorKey = "has_error"
private const val HadInternetKey = "had_internet"

private var fetchId = 1

private val context: Context = MobilePathApplication.instance
private val prefs = context.getSharedPreferences("widget_data_store", Context.MODE_PRIVATE)

Expand Down Expand Up @@ -59,6 +63,7 @@ object AndroidWidgetDataRepository {
startFetch(
force = false,
canRefreshLocation = false,
fetchId = 0,
).previous?.value
)
)
Expand Down Expand Up @@ -101,10 +106,14 @@ object AndroidWidgetDataRepository {
isBackgroundUpdate: Boolean,
) = coroutineScope {
if (isLoading && hasLoadedOnce) {
Logging.d("WDR: join fetch $fetchId")
return@coroutineScope
}

val (fetch, previous) = startFetch(force, canRefreshLocation, isBackgroundUpdate)
val fetchId = fetchId++
Logging.d("WDR: start fetch $fetchId")

val (fetch, previous) = startFetch(force, canRefreshLocation, isBackgroundUpdate, fetchId)

hasLoadedOnce = true
isLoading = true
Expand All @@ -117,9 +126,13 @@ object AndroidWidgetDataRepository {

isLoading = false
if (result.isFailure()) {
Logging.w("WDR: fetch $fetchId error loading widget data", result.error)
hasError = true
hadInternet = result.hadInternet
} else if (result.isSuccess()) {
Logging.d("WDR: fetch $fetchId completed successfully")
}

_data.await().value = result
DepartureBoardWidget.onDataChanged()
}
Expand All @@ -128,6 +141,7 @@ object AndroidWidgetDataRepository {
force: Boolean,
canRefreshLocation: Boolean,
isBackgroundUpdate: Boolean = !AppLifecycleObserver.isActive.value,
fetchId: Int,
): FetchWithPrevious<WidgetData> {
val anyWidgetsUseLocation =
WidgetConfigurationManager.getWidgetConfigurations().values.any { it.useClosestStation }
Expand All @@ -144,7 +158,9 @@ object AndroidWidgetDataRepository {
staleness = Staleness(
staleAfter = if (force) 5.seconds else 30.seconds,
invalidAfter = Duration.INFINITE, // Always show old data while loading widget.
)
),
fetchId = fetchId,

)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ import com.sixbynine.transit.path.MobilePathApplication
import com.sixbynine.transit.path.api.Stations
import com.sixbynine.transit.path.api.TrainFilter
import com.sixbynine.transit.path.api.anyMatch
import com.sixbynine.transit.path.time.NewYorkTimeZone
import com.sixbynine.transit.path.time.now
import com.sixbynine.transit.path.time.today
import com.sixbynine.transit.path.util.DataResult
import com.sixbynine.transit.path.util.dropSubSeconds
import com.sixbynine.transit.path.util.map
import com.sixbynine.transit.path.widget.configuration.StoredWidgetConfiguration
import com.sixbynine.transit.path.widget.configuration.WidgetConfigurationManager
Expand All @@ -35,6 +37,7 @@ import kotlinx.datetime.Instant
import kotlinx.datetime.TimeZone
import kotlinx.datetime.atTime
import kotlinx.datetime.toInstant
import kotlinx.datetime.toLocalDateTime
import java.util.Locale

class DepartureBoardWidget : GlanceAppWidget() {
Expand All @@ -45,13 +48,14 @@ class DepartureBoardWidget : GlanceAppWidget() {
launch { WidgetRefreshWorker.schedule() }

val data = AndroidWidgetDataRepository.getData()
Logging.d("provideGlance")

provideContent {
val updateTime =
currentState(key = LastUpdateKey)
?.let { Instant.fromEpochMilliseconds(it) } ?: now()
val configuration = with(WidgetConfigurationManager) { getWidgetConfiguration() }
Logging.d("provideContent invoked, updateTime = $updateTime")
Logging.d("provideContent invoked, updateTime = ${updateTime.toLocalDateTime(
NewYorkTimeZone).dropSubSeconds()}")

val widgetState = if (configuration.needsSetup()) {
WidgetState(
Expand All @@ -68,7 +72,6 @@ class DepartureBoardWidget : GlanceAppWidget() {
)
}
WidgetContent(widgetState)
Logging.d("composed widget content with data fetched at ${widgetState.result.data?.fetchTime}")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.WorkerParameters
import com.sixbynine.transit.path.Logging
import com.sixbynine.transit.path.MobilePathApplication
import com.sixbynine.transit.path.api.PathApi
import com.sixbynine.transit.path.time.now
import com.sixbynine.transit.path.util.Staleness
import com.sixbynine.transit.path.util.await
import com.sixbynine.transit.path.util.isSuccess
import com.sixbynine.transit.path.util.onFailure
import java.util.concurrent.TimeUnit
import kotlin.time.Duration
Expand All @@ -34,6 +36,8 @@ class WidgetRefreshWorker(

val isBackground = params.inputData.getBoolean(IS_BACKGROUND, true)

Logging.d("Refresh widget data from worker, isBackground=$isBackground")

PathApi.instance
.getUpcomingDepartures(
now = now(),
Expand All @@ -46,6 +50,9 @@ class WidgetRefreshWorker(
return Result.success()
}
}
.also {
Logging.d("Refresh widget data from worker complete, isBackground=$isBackground, wasSuccess=${it.isSuccess()}")
}

AndroidWidgetDataRepository.refreshWidgetData(
force = false,
Expand Down Expand Up @@ -93,11 +100,18 @@ class WidgetRefreshWorker(
}

val workManager = WorkManager.getInstance(context)
val workRequest = OneTimeWorkRequestBuilder<WidgetRefreshWorker>().setInputData(
Data.Builder()
.putBoolean(IS_BACKGROUND, false)
.build()
).build()
val workRequest = OneTimeWorkRequestBuilder<WidgetRefreshWorker>()
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(CONNECTED)
.build()
)
.setInputData(
Data.Builder()
.putBoolean(IS_BACKGROUND, false)
.build()
)
.build()
workManager.enqueueUniqueWork(ONE_TIME_WORK_TAG, ExistingWorkPolicy.KEEP, workRequest)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,22 @@ import com.sixbynine.transit.path.Logging
import com.sixbynine.transit.path.MainActivity
import com.sixbynine.transit.path.R.drawable
import com.sixbynine.transit.path.app.ui.ColorWrapper
import com.sixbynine.transit.path.time.NewYorkTimeZone
import com.sixbynine.transit.path.util.DataResult
import com.sixbynine.transit.path.util.dropSubSeconds
import com.sixbynine.transit.path.util.secondOrNull
import com.sixbynine.transit.path.widget.WidgetData
import com.sixbynine.transit.path.widget.WidgetDataFormatter
import com.sixbynine.transit.path.widget.glance.GlanceTheme
import com.sixbynine.transit.path.widget.glance.Text
import kotlinx.datetime.toLocalDateTime

@Composable
fun DepartureBoard(result: DataResult<WidgetData>, modifier: GlanceModifier = GlanceModifier) {
Logging.d("compose departure board with data fetched at ${result.data?.fetchTime}")
Logging.d(
"compose departure board with data fetched at " +
result.data?.fetchTime?.toLocalDateTime(NewYorkTimeZone)?.time?.dropSubSeconds()
)
LazyColumn(modifier) {
if (VERSION.SDK_INT >= 31) {
item {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ enum class TrainFilter(override val number: Int) : IntPersistable {
if (filter == All) return true

return when {
// Trains to/from WTC are always interstate.
station == Stations.WorldTradeCenter ||
destination == Stations.WorldTradeCenter -> true
// Newport -> Hoboken is the only time an NJ-terminating train travels east.
destination == Stations.Hoboken -> station.isInNewYork
station.isInNewYork -> destination.isInNewJersey || destination isWestOf station
Expand Down
Loading

0 comments on commit 5c6e97a

Please sign in to comment.