Loading .gitlab-ci.yml +2 −0 Original line number Diff line number Diff line Loading @@ -160,6 +160,7 @@ test: # Build debug APKs for each architecture - cd cardinal-android - touch local.properties - ./gradlew generateUniFFIBindings - ./gradlew test --info --stacktrace --no-daemon - ./gradlew assembleArm64Debug --info --stacktrace --no-daemon artifacts: Loading Loading @@ -257,6 +258,7 @@ build_release: - touch local.properties - | # Build APKs for each architecture ./gradlew generateUniFFIBindings ./gradlew assembleArm64Release --info --stacktrace --no-daemon ./gradlew assembleX86_64Release --info --stacktrace --no-daemon artifacts: Loading cardinal-android/app/build.gradle.kts +0 −9 Original line number Diff line number Diff line Loading @@ -137,15 +137,6 @@ android { dependsOn("buildCargoNdkArm64Release", "buildCargoNdkX86_64Release") } applicationVariants.all { val variant = this // Add dependency from Java compilation to the UniFFI binding generation task tasks.named("compile${variant.name.capitalize()}JavaWithJavac") { dependsOn(generateUniFFIBindings) } } sourceSets { getByName("main") { java.srcDir(layout.buildDirectory.dir("generated/source/uniffi")) Loading cardinal-android/app/src/main/java/earth/maps/cardinal/ui/home/OfflineAreasViewModel.kt +45 −40 Original line number Diff line number Diff line Loading @@ -23,7 +23,6 @@ import android.content.Context import android.content.Intent import android.content.ServiceConnection import android.os.IBinder import android.util.Log import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf Loading @@ -39,6 +38,8 @@ import earth.maps.cardinal.tileserver.TileDownloadForegroundService import earth.maps.cardinal.tileserver.calculateTileRange import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch import javax.inject.Inject import kotlin.math.min Loading @@ -60,6 +61,10 @@ class OfflineAreasViewModel @Inject constructor( val unifiedProgress = mutableFloatStateOf(0f) // 0.0 to 1.0 val currentStage = mutableStateOf(DownloadStage.BASEMAP) // Error handling private val _errorMessage = MutableStateFlow<String?>(null) val errorMessage: StateFlow<String?> = _errorMessage // Service binding infrastructure private var serviceBinder: TileDownloadForegroundService.TileDownloadBinder? = null private var progressJob: Job? = null Loading @@ -67,14 +72,12 @@ class OfflineAreasViewModel @Inject constructor( private val serviceConnection = object : ServiceConnection { override fun onServiceConnected(name: ComponentName?, service: IBinder?) { Log.d(TAG, "Connected to TileDownloadForegroundService") serviceBinder = service as TileDownloadForegroundService.TileDownloadBinder isBound = true syncWithOngoingDownloads() } override fun onServiceDisconnected(name: ComponentName?) { Log.d(TAG, "Disconnected from TileDownloadForegroundService") serviceBinder = null isBound = false progressJob?.cancel() Loading @@ -84,7 +87,6 @@ class OfflineAreasViewModel @Inject constructor( } override fun onBindingDied(name: ComponentName?) { Log.d(TAG, "Binding to TileDownloadForegroundService died") serviceBinder = null isBound = false progressJob?.cancel() Loading @@ -93,7 +95,6 @@ class OfflineAreasViewModel @Inject constructor( } override fun onNullBinding(name: ComponentName?) { Log.d(TAG, "Null binding to TileDownloadForegroundService") serviceBinder = null isBound = false resetProgressState() Loading @@ -118,13 +119,8 @@ class OfflineAreasViewModel @Inject constructor( // Check if service is currently downloading val isServiceDownloading = service.isDownloading.value if (isServiceDownloading) { Log.d(TAG, "Detected ongoing download in service, syncing UI state") // The StateFlow observations should handle the rest } else { Log.d(TAG, "No ongoing downloads detected in service") } } else { Log.d(TAG, "Service not bound yet, will sync when connection established") } } } Loading Loading @@ -184,9 +180,12 @@ class OfflineAreasViewModel @Inject constructor( */ private fun bindToService() { if (!isBound) { Log.d(TAG, "Binding to TileDownloadForegroundService") val intent = Intent(context, TileDownloadForegroundService::class.java) try { context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE) } catch (e: Exception) { _errorMessage.value = "Failed to bind to download service: ${e.message}" } } } Loading @@ -195,8 +194,11 @@ class OfflineAreasViewModel @Inject constructor( */ private fun unbindFromService() { if (isBound) { Log.d(TAG, "Unbinding from TileDownloadForegroundService") try { context.unbindService(serviceConnection) } catch (e: Exception) { _errorMessage.value = "Failed to unbind from download service: ${e.message}" } serviceBinder = null isBound = false } Loading @@ -220,9 +222,6 @@ class OfflineAreasViewModel @Inject constructor( downloadProgress.intValue = 0 totalTiles.intValue = 0 currentAreaName.value = "" Log.d(TAG, "Reset progress state - no active downloads in database") } else { Log.d(TAG, "Not resetting progress state - active areas exist in database") } } Loading @@ -237,6 +236,12 @@ class OfflineAreasViewModel @Inject constructor( companion object { const val OFFLINE_AREA_MIN_ZOOM = 5 const val OFFLINE_AREA_MAX_ZOOM = 14 private const val TAG = "OfflineAreasViewModel" } /** * Clear any error message */ fun clearErrorMessage() { _errorMessage.value = null } } cardinal-android/app/src/main/java/earth/maps/cardinal/ui/place/TransitStopCardViewModel.kt +0 −18 Original line number Diff line number Diff line Loading @@ -28,14 +28,11 @@ import earth.maps.cardinal.data.Place import earth.maps.cardinal.data.room.SavedPlaceDao import earth.maps.cardinal.transit.StopTime import earth.maps.cardinal.transit.TransitousService import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch import javax.inject.Inject import kotlin.time.Duration.Companion.seconds @HiltViewModel class TransitStopCardViewModel @Inject constructor( Loading @@ -44,8 +41,6 @@ class TransitStopCardViewModel @Inject constructor( private val appPreferenceRepository: AppPreferenceRepository, ) : ViewModel() { private var refreshJob: Job? = null val isPlaceSaved = mutableStateOf(false) val stop = mutableStateOf<Place?>(null) val departures = MutableStateFlow<List<StopTime>>(emptyList()) Loading Loading @@ -73,15 +68,6 @@ class TransitStopCardViewModel @Inject constructor( val use24HourFormat = appPreferenceRepository.use24HourFormat init { refreshJob = viewModelScope.launch { while (true) { refreshDepartures() delay(30.seconds) } } } fun setStop(place: Place) { this.stop.value = place } Loading Loading @@ -139,10 +125,6 @@ class TransitStopCardViewModel @Inject constructor( } } override fun onCleared() { super.onCleared() refreshJob?.cancel() } companion object { private const val TAG = "TransitStopViewModel" Loading cardinal-android/app/src/main/java/earth/maps/cardinal/ui/settings/SettingsViewModel.kt +0 −8 Original line number Diff line number Diff line Loading @@ -158,12 +158,4 @@ class SettingsViewModel @Inject constructor( } return null } fun onCallToActionClicked() { val url = "https://github.com/ellenhp/cardinal" val i = Intent(Intent.ACTION_VIEW) i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) i.setData(url.toUri()) context.startActivity(i) } } Loading
.gitlab-ci.yml +2 −0 Original line number Diff line number Diff line Loading @@ -160,6 +160,7 @@ test: # Build debug APKs for each architecture - cd cardinal-android - touch local.properties - ./gradlew generateUniFFIBindings - ./gradlew test --info --stacktrace --no-daemon - ./gradlew assembleArm64Debug --info --stacktrace --no-daemon artifacts: Loading Loading @@ -257,6 +258,7 @@ build_release: - touch local.properties - | # Build APKs for each architecture ./gradlew generateUniFFIBindings ./gradlew assembleArm64Release --info --stacktrace --no-daemon ./gradlew assembleX86_64Release --info --stacktrace --no-daemon artifacts: Loading
cardinal-android/app/build.gradle.kts +0 −9 Original line number Diff line number Diff line Loading @@ -137,15 +137,6 @@ android { dependsOn("buildCargoNdkArm64Release", "buildCargoNdkX86_64Release") } applicationVariants.all { val variant = this // Add dependency from Java compilation to the UniFFI binding generation task tasks.named("compile${variant.name.capitalize()}JavaWithJavac") { dependsOn(generateUniFFIBindings) } } sourceSets { getByName("main") { java.srcDir(layout.buildDirectory.dir("generated/source/uniffi")) Loading
cardinal-android/app/src/main/java/earth/maps/cardinal/ui/home/OfflineAreasViewModel.kt +45 −40 Original line number Diff line number Diff line Loading @@ -23,7 +23,6 @@ import android.content.Context import android.content.Intent import android.content.ServiceConnection import android.os.IBinder import android.util.Log import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf Loading @@ -39,6 +38,8 @@ import earth.maps.cardinal.tileserver.TileDownloadForegroundService import earth.maps.cardinal.tileserver.calculateTileRange import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch import javax.inject.Inject import kotlin.math.min Loading @@ -60,6 +61,10 @@ class OfflineAreasViewModel @Inject constructor( val unifiedProgress = mutableFloatStateOf(0f) // 0.0 to 1.0 val currentStage = mutableStateOf(DownloadStage.BASEMAP) // Error handling private val _errorMessage = MutableStateFlow<String?>(null) val errorMessage: StateFlow<String?> = _errorMessage // Service binding infrastructure private var serviceBinder: TileDownloadForegroundService.TileDownloadBinder? = null private var progressJob: Job? = null Loading @@ -67,14 +72,12 @@ class OfflineAreasViewModel @Inject constructor( private val serviceConnection = object : ServiceConnection { override fun onServiceConnected(name: ComponentName?, service: IBinder?) { Log.d(TAG, "Connected to TileDownloadForegroundService") serviceBinder = service as TileDownloadForegroundService.TileDownloadBinder isBound = true syncWithOngoingDownloads() } override fun onServiceDisconnected(name: ComponentName?) { Log.d(TAG, "Disconnected from TileDownloadForegroundService") serviceBinder = null isBound = false progressJob?.cancel() Loading @@ -84,7 +87,6 @@ class OfflineAreasViewModel @Inject constructor( } override fun onBindingDied(name: ComponentName?) { Log.d(TAG, "Binding to TileDownloadForegroundService died") serviceBinder = null isBound = false progressJob?.cancel() Loading @@ -93,7 +95,6 @@ class OfflineAreasViewModel @Inject constructor( } override fun onNullBinding(name: ComponentName?) { Log.d(TAG, "Null binding to TileDownloadForegroundService") serviceBinder = null isBound = false resetProgressState() Loading @@ -118,13 +119,8 @@ class OfflineAreasViewModel @Inject constructor( // Check if service is currently downloading val isServiceDownloading = service.isDownloading.value if (isServiceDownloading) { Log.d(TAG, "Detected ongoing download in service, syncing UI state") // The StateFlow observations should handle the rest } else { Log.d(TAG, "No ongoing downloads detected in service") } } else { Log.d(TAG, "Service not bound yet, will sync when connection established") } } } Loading Loading @@ -184,9 +180,12 @@ class OfflineAreasViewModel @Inject constructor( */ private fun bindToService() { if (!isBound) { Log.d(TAG, "Binding to TileDownloadForegroundService") val intent = Intent(context, TileDownloadForegroundService::class.java) try { context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE) } catch (e: Exception) { _errorMessage.value = "Failed to bind to download service: ${e.message}" } } } Loading @@ -195,8 +194,11 @@ class OfflineAreasViewModel @Inject constructor( */ private fun unbindFromService() { if (isBound) { Log.d(TAG, "Unbinding from TileDownloadForegroundService") try { context.unbindService(serviceConnection) } catch (e: Exception) { _errorMessage.value = "Failed to unbind from download service: ${e.message}" } serviceBinder = null isBound = false } Loading @@ -220,9 +222,6 @@ class OfflineAreasViewModel @Inject constructor( downloadProgress.intValue = 0 totalTiles.intValue = 0 currentAreaName.value = "" Log.d(TAG, "Reset progress state - no active downloads in database") } else { Log.d(TAG, "Not resetting progress state - active areas exist in database") } } Loading @@ -237,6 +236,12 @@ class OfflineAreasViewModel @Inject constructor( companion object { const val OFFLINE_AREA_MIN_ZOOM = 5 const val OFFLINE_AREA_MAX_ZOOM = 14 private const val TAG = "OfflineAreasViewModel" } /** * Clear any error message */ fun clearErrorMessage() { _errorMessage.value = null } }
cardinal-android/app/src/main/java/earth/maps/cardinal/ui/place/TransitStopCardViewModel.kt +0 −18 Original line number Diff line number Diff line Loading @@ -28,14 +28,11 @@ import earth.maps.cardinal.data.Place import earth.maps.cardinal.data.room.SavedPlaceDao import earth.maps.cardinal.transit.StopTime import earth.maps.cardinal.transit.TransitousService import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch import javax.inject.Inject import kotlin.time.Duration.Companion.seconds @HiltViewModel class TransitStopCardViewModel @Inject constructor( Loading @@ -44,8 +41,6 @@ class TransitStopCardViewModel @Inject constructor( private val appPreferenceRepository: AppPreferenceRepository, ) : ViewModel() { private var refreshJob: Job? = null val isPlaceSaved = mutableStateOf(false) val stop = mutableStateOf<Place?>(null) val departures = MutableStateFlow<List<StopTime>>(emptyList()) Loading Loading @@ -73,15 +68,6 @@ class TransitStopCardViewModel @Inject constructor( val use24HourFormat = appPreferenceRepository.use24HourFormat init { refreshJob = viewModelScope.launch { while (true) { refreshDepartures() delay(30.seconds) } } } fun setStop(place: Place) { this.stop.value = place } Loading Loading @@ -139,10 +125,6 @@ class TransitStopCardViewModel @Inject constructor( } } override fun onCleared() { super.onCleared() refreshJob?.cancel() } companion object { private const val TAG = "TransitStopViewModel" Loading
cardinal-android/app/src/main/java/earth/maps/cardinal/ui/settings/SettingsViewModel.kt +0 −8 Original line number Diff line number Diff line Loading @@ -158,12 +158,4 @@ class SettingsViewModel @Inject constructor( } return null } fun onCallToActionClicked() { val url = "https://github.com/ellenhp/cardinal" val i = Intent(Intent.ACTION_VIEW) i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) i.setData(url.toUri()) context.startActivity(i) } }