Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
3b8393e
Add water sources layer from OSM (shared + Android)
indiana Sep 28, 2026
219f36c
Add water sources layer from OSM (iOS)
indiana Sep 28, 2026
8339d43
Remove minimum zoom from water sources layer
indiana Sep 28, 2026
773a3e9
Group water layer toggles: parent Woda with drinking/springs/wells
indiana Sep 28, 2026
33fd724
Merge pull request #60 from indiana/feature/water-sources
indiana Sep 28, 2026
9e05f33
Bump iOS build number to 64 for TestFlight
indiana Sep 28, 2026
6a19c55
Bump iOS marketing version to 1.5 for TestFlight
indiana Sep 28, 2026
6c0e513
Enrich water sources with pump, seasonality, refill and water-on-site…
indiana Sep 29, 2026
4bde9a6
Fold refill and water-on-site into the drinking water group (3 checkb…
indiana Sep 29, 2026
f4dc23b
Complete water source label translations and show fountain/bottle info
indiana Sep 29, 2026
20ae801
Keep base map and offline tiles visible above their max zoom (overzoom)
indiana Sep 29, 2026
4eb147c
Rename water source operator/description fields for Swift interop
indiana Sep 29, 2026
cfb8df3
Update water parser test for renamed operator/description fields
indiana Sep 29, 2026
e371e27
Merge pull request #61 from indiana/feature/water-sources-p1p2
indiana Sep 29, 2026
179eca8
Bump iOS build number to 65 for TestFlight
indiana Sep 29, 2026
c89ae72
Show OSM water data version and fetch date in About screen
indiana Oct 1, 2026
26510ae
Merge pull request #62 from indiana/feature/about-osm-data-info
indiana Oct 1, 2026
a4d2a49
Bump iOS build number to 66 for TestFlight
indiana Oct 1, 2026
f473c38
Bump Android versionCode 23 / versionName 1.22
indiana Oct 1, 2026
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
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ android {
applicationId = "com.indiana.zwl"
minSdk = 26
targetSdk = 36
versionCode = 22
versionName = "1.21"
versionCode = 23
versionName = "1.22"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
Expand Down
1 change: 1 addition & 0 deletions app/src/main/assets/water-baseline.geojson

Large diffs are not rendered by default.

22 changes: 18 additions & 4 deletions app/src/main/java/com/indiana/zwl/data/sync/SyncWorker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import com.indiana.zwl.domain.usecase.SyncForestBansUseCase
import com.indiana.zwl.domain.usecase.SyncPoiUseCase
import com.indiana.zwl.domain.usecase.SyncWaterSourcesUseCase
import com.indiana.zwl.domain.usecase.SyncZonesUseCase
import androidx.hilt.work.HiltWorker
import dagger.assisted.Assisted
Expand All @@ -19,19 +20,32 @@ class SyncWorker @AssistedInject constructor(
@Assisted workerParams: WorkerParameters,
private val syncZonesUseCase: SyncZonesUseCase,
private val syncPoiUseCase: SyncPoiUseCase,
private val syncForestBansUseCase: SyncForestBansUseCase
private val syncForestBansUseCase: SyncForestBansUseCase,
private val syncWaterSourcesUseCase: SyncWaterSourcesUseCase
) : CoroutineWorker(appContext, workerParams) {

override suspend fun doWork(): Result {
return try {
val (zonesResult, poiResult, bansResult) = coroutineScope {
var zonesOk = false
var poiOk = false
var bansOk = false

coroutineScope {
val zonesDeferred = async { syncZonesUseCase() }
val poiDeferred = async { syncPoiUseCase() }
val bansDeferred = async { syncForestBansUseCase() }
Triple(zonesDeferred.await(), poiDeferred.await(), bansDeferred.await())
val waterDeferred = async { syncWaterSourcesUseCase() }

zonesOk = zonesDeferred.await().isSuccess
poiOk = poiDeferred.await().isSuccess
bansOk = bansDeferred.await().isSuccess
val waterResult = waterDeferred.await()
if (waterResult.isFailure) {
waterResult.exceptionOrNull()?.printStackTrace()
}
}

if (zonesResult.isSuccess && poiResult.isSuccess && bansResult.isSuccess) {
if (zonesOk && poiOk && bansOk) {
Result.success()
} else {
Result.retry()
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/java/com/indiana/zwl/di/NetworkModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.indiana.zwl.shared.data.remote.BdlArcgisApi
import com.indiana.zwl.shared.data.remote.BdlFireApi
import com.indiana.zwl.shared.data.remote.BdlOgcApi
import com.indiana.zwl.shared.data.remote.BdlStandDescriptionApi
import com.indiana.zwl.shared.data.water.WaterSyncManager
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
Expand Down Expand Up @@ -62,4 +63,10 @@ object NetworkModule {
): GetForestStandForPointUseCase {
return GetForestStandForPointUseCase(GetForestStandUseCase(ogcApi), soilCoverUseCase)
}

@Provides
@Singleton
fun provideWaterSyncManager(): WaterSyncManager {
return get(WaterSyncManager::class.java)
}
}
7 changes: 7 additions & 0 deletions app/src/main/java/com/indiana/zwl/di/RepositoryModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.indiana.zwl.domain.repository.ForestBanRepository
import com.indiana.zwl.domain.repository.OfflineAreaRepository
import com.indiana.zwl.domain.repository.PoiRepository
import com.indiana.zwl.domain.repository.SavedPointRepository
import com.indiana.zwl.domain.repository.WaterSourceRepository
import com.indiana.zwl.domain.repository.ZoneRepository
import dagger.Module
import dagger.Provides
Expand Down Expand Up @@ -45,4 +46,10 @@ object RepositoryModule {
fun provideOfflineAreaRepository(): OfflineAreaRepository {
return get(OfflineAreaRepository::class.java)
}

@Provides
@Singleton
fun provideWaterSourceRepository(): WaterSourceRepository {
return get(WaterSourceRepository::class.java)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.indiana.zwl.domain.usecase

import com.indiana.zwl.shared.data.water.WaterSyncManager
import com.indiana.zwl.shared.data.water.WaterSyncOutcome
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import javax.inject.Inject

class SyncWaterSourcesUseCase @Inject constructor(
private val waterSyncManager: WaterSyncManager
) {
suspend operator fun invoke(): Result<WaterSyncOutcome> = withContext(Dispatchers.IO) {
try {
waterSyncManager.refreshIfStale()
} catch (e: Exception) {
if (e is CancellationException) throw e
e.printStackTrace()
Result.failure(e)
}
}
}
82 changes: 82 additions & 0 deletions app/src/main/java/com/indiana/zwl/presentation/AboutScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,11 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.indiana.zwl.BuildConfig
import com.indiana.zwl.R
import com.indiana.zwl.domain.model.WaterDataState
import com.indiana.zwl.presentation.theme.DarkForestBackground
import com.indiana.zwl.presentation.theme.ForestGreenAccent
import com.indiana.zwl.presentation.theme.ForestGreenText
import com.indiana.zwl.shared.data.water.WaterAttribution

private const val BDL_PORTAL_URL = "https://www.bdl.lasy.gov.pl/portal/"
private const val IBL_FIRE_URL = "https://bazapozarow.ibles.pl/"
Expand All @@ -67,6 +69,7 @@ private const val INSTAGRAM_URL = "https://instagram.com/legalny.bushcraft"
@Composable
fun AboutScreen(
onClose: () -> Unit,
waterDataState: WaterDataState? = null,
modifier: Modifier = Modifier
) {
val isLandscape =
Expand Down Expand Up @@ -205,6 +208,50 @@ fun AboutScreen(
}
}

Card(
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface),
shape = RoundedCornerShape(12.dp)
) {
Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(
imageVector = Icons.Default.Public,
contentDescription = null,
tint = ForestGreenAccent,
modifier = Modifier.size(20.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = "Dane źródeł wody (OSM)",
fontSize = 15.sp,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.onSurface
)
}

Text(
text = "Punkty wody pitnej, źródeł, studni i napełniania butelek pochodzą z OpenStreetMap i odświeżają się automatycznie.",
fontSize = 13.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant,
lineHeight = 19.sp
)

DataRow(label = "Wersja danych", value = waterVersionLabel(waterDataState?.dataVersion))
DataRow(label = "Data pobrania", value = waterFetchedAtLabel(waterDataState?.lastCheckedAt))
DataRow(label = "Liczba punktów", value = waterDataState?.count?.toString() ?: "—")

Text(
text = WaterAttribution.OSM,
fontSize = 11.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}

Card(
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface),
Expand Down Expand Up @@ -377,3 +424,38 @@ private fun SourceLinkRow(label: String, url: String) {
)
}
}

@Composable
private fun DataRow(label: String, value: String) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = label,
fontSize = 13.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
text = value,
fontSize = 13.sp,
fontWeight = FontWeight.Medium,
color = MaterialTheme.colorScheme.onSurface
)
}
}

private fun waterVersionLabel(version: Long?): String {
if (version == null || version <= 0L) return "—"
val year = version / 10000
val month = (version / 100) % 100
val day = version % 100
return String.format(java.util.Locale.US, "%04d-%02d-%02d", year, month, day)
}

private fun waterFetchedAtLabel(millis: Long?): String {
if (millis == null || millis <= 0L) return "zestaw wbudowany"
return java.text.SimpleDateFormat("yyyy-MM-dd HH:mm", java.util.Locale.getDefault())
.format(java.util.Date(millis))
}
6 changes: 5 additions & 1 deletion app/src/main/java/com/indiana/zwl/presentation/MainScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ fun MainScreen(
val savedPoints by viewModel.savedPoints.collectAsStateWithLifecycle()
val showSavedPointList by viewModel.showSavedPointList.collectAsStateWithLifecycle()
val selectedSavedPointInfo by viewModel.selectedSavedPointInfo.collectAsStateWithLifecycle()
val waterDataState by viewModel.waterDataState.collectAsStateWithLifecycle()
val savedPointDetailViewModel: SavedPointDetailViewModel = hiltViewModel()
val selectedSavedPointDetails by savedPointDetailViewModel.details.collectAsStateWithLifecycle()
var selectedTab by rememberSaveable { mutableStateOf(0) }
Expand Down Expand Up @@ -459,7 +460,10 @@ fun MainScreen(
)

if (showAbout) {
AboutScreen(onClose = { showAbout = false })
AboutScreen(
waterDataState = waterDataState,
onClose = { showAbout = false }
)
}

if (showSavedPointList) {
Expand Down
Loading
Loading