Skip to content

Commit

Permalink
Merge pull request #125 from CrisisCleanup/onsite-fixes
Browse files Browse the repository at this point in the history
Onsite fixes
  • Loading branch information
hueachilles authored Oct 31, 2024
2 parents 1e92160 + da06b74 commit 26ff95c
Show file tree
Hide file tree
Showing 31 changed files with 596 additions and 91 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ plugins {

android {
defaultConfig {
val buildVersion = 234
val buildVersion = 236
applicationId = "com.crisiscleanup"
versionCode = buildVersion
versionName = "0.9.${buildVersion - 168}"
Expand Down
15 changes: 13 additions & 2 deletions app/src/main/java/com/crisiscleanup/MainActivityViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import com.crisiscleanup.core.data.repository.AccountUpdateRepository
import com.crisiscleanup.core.data.repository.AppDataManagementRepository
import com.crisiscleanup.core.data.repository.LocalAppMetricsRepository
import com.crisiscleanup.core.data.repository.LocalAppPreferencesRepository
import com.crisiscleanup.core.data.repository.ShareLocationRepository
import com.crisiscleanup.core.model.data.AccountData
import com.crisiscleanup.core.model.data.AppMetricsData
import com.crisiscleanup.core.model.data.AppOpenInstant
Expand Down Expand Up @@ -80,6 +81,7 @@ class MainActivityViewModel @Inject constructor(
externalEventBus: ExternalEventBus,
private val accountEventBus: AccountEventBus,
private val networkMonitor: NetworkMonitor,
private val shareLocationRepository: ShareLocationRepository,
@Dispatcher(IO) private val ioDispatcher: CoroutineDispatcher,
@Logger(CrisisCleanupLoggers.App) private val logger: AppLogger,
) : ViewModel() {
Expand Down Expand Up @@ -151,8 +153,6 @@ class MainActivityViewModel @Inject constructor(
started = SharingStarted.WhileSubscribed(),
)

val translationCount = translator.translationCount

val buildEndOfLife: BuildEndOfLife?
get() {
if (appEnv.isEarlybird) {
Expand Down Expand Up @@ -224,7 +224,10 @@ class MainActivityViewModel @Inject constructor(

appPreferencesRepository.userPreferences.onEach {
firebaseAnalytics.setAnalyticsCollectionEnabled(it.allowAllAnalytics)

shareLocationWithOrganization()
}
.flowOn(ioDispatcher)
.launchIn(viewModelScope)

syncPuller.appPullLanguage()
Expand Down Expand Up @@ -271,6 +274,10 @@ class MainActivityViewModel @Inject constructor(
}
}
}

viewModelScope.launch(ioDispatcher) {
shareLocationWithOrganization()
}
}

fun onRejectTerms() {
Expand Down Expand Up @@ -327,6 +334,10 @@ class MainActivityViewModel @Inject constructor(
accountEventBus.onLogout()
accountEventBus.clearAccountInactiveOrganization()
}

private suspend fun shareLocationWithOrganization() {
shareLocationRepository.shareLocation()
}
}

sealed interface MainActivityViewState {
Expand Down
9 changes: 8 additions & 1 deletion app/src/main/java/com/crisiscleanup/ui/AppNavigation.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.VerticalDivider
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavDestination
import androidx.navigation.NavDestination.Companion.hierarchy
import com.crisiscleanup.core.designsystem.LocalAppTranslator
Expand Down Expand Up @@ -67,8 +70,12 @@ private fun NavItems(
@Composable () -> Unit,
) -> Unit,
) {
val t = LocalAppTranslator.current
val translationCount by t.translationCount.collectAsStateWithLifecycle()
destinations.forEachIndexed { i, destination ->
val title = LocalAppTranslator.current(destination.titleTranslateKey)
val title = remember(translationCount) {
t(destination.titleTranslateKey)
}
val selected = currentDestination.isTopLevelDestinationInHierarchy(destination)
itemContent(
selected,
Expand Down
13 changes: 5 additions & 8 deletions app/src/main/java/com/crisiscleanup/ui/CrisisCleanupApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ fun CrisisCleanupApp(

val isOffline by appState.isOffline.collectAsStateWithLifecycle()

val translationCount by viewModel.translationCount.collectAsStateWithLifecycle()
val t = viewModel.translator

LaunchedEffect(isOffline) {
Expand Down Expand Up @@ -132,7 +131,6 @@ fun CrisisCleanupApp(
appState,
viewModel,
authState,
translationCount,
)
}
}
Expand All @@ -147,7 +145,6 @@ private fun BoxScope.LoadedContent(
appState: CrisisCleanupAppState,
viewModel: MainActivityViewModel,
authState: AuthState,
translationCount: Int = 0,
) {
val isAccountExpired = viewModel.isAccountExpired
val hasAcceptedTerms = viewModel.hasAcceptedTerms
Expand Down Expand Up @@ -229,7 +226,7 @@ private fun BoxScope.LoadedContent(
isAccountExpired &&
!appState.hideLoginAlert
) {
ExpiredAccountAlert(snackbarHostState, translationCount) {
ExpiredAccountAlert(snackbarHostState) {
openAuthentication = true
}
}
Expand Down Expand Up @@ -451,12 +448,12 @@ private fun NavigableContent(
@Composable
private fun ExpiredAccountAlert(
snackbarHostState: SnackbarHostState,
translationCount: Int,
openAuthentication: () -> Unit,
) {
val translator = LocalAppTranslator.current
val message = translator("info.log_in_for_updates")
val loginText = translator("actions.login", authenticationR.string.login)
val t = LocalAppTranslator.current
val translationCount by t.translationCount.collectAsStateWithLifecycle()
val message = t("info.log_in_for_updates")
val loginText = t("actions.login", authenticationR.string.login)
LaunchedEffect(translationCount) {
val result = snackbarHostState.showSnackbar(
message,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ class GooglePlaceAddressSearchRepository @Inject constructor(
.build()
val response = placesClient().fetchPlace(request).await()
val addressTypeKeys = setOf(
"subpremise",
"street_number",
"route",
"locality",
Expand All @@ -178,8 +179,9 @@ class GooglePlaceAddressSearchRepository @Inject constructor(
latitude = coordinates.latitude,
longitude = coordinates.longitude,
address = listOf(
addressComponentLookup["street_number"] ?: "",
addressComponentLookup["route"] ?: "",
addressComponentLookup["street_number"],
addressComponentLookup["route"],
addressComponentLookup["subpremise"],
).combineTrimText(),
city = addressComponentLookup["locality"] ?: "",
county = addressComponentLookup["administrative_area_level_2"] ?: "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ import java.net.URLDecoder
import java.net.URLEncoder
import java.nio.charset.StandardCharsets

fun Collection<String?>.filterNotBlankTrim(): List<String> {
val notBlank = filter { it?.isNotBlank() == true }.filterNotNull()
return notBlank.map(String::trim)
}
fun Collection<String?>.filterNotBlankTrim() = filter { it?.isNotBlank() == true }
.filterNotNull()
.map(String::trim)

fun Collection<String?>.combineTrimText(separator: String = ", ") =
filterNotBlankTrim().joinToString(separator)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import com.crisiscleanup.core.data.repository.CrisisCleanupListsRepository
import com.crisiscleanup.core.data.repository.CrisisCleanupLocalImageRepository
import com.crisiscleanup.core.data.repository.CrisisCleanupOrgVolunteerRepository
import com.crisiscleanup.core.data.repository.CrisisCleanupRequestRedeployRepository
import com.crisiscleanup.core.data.repository.CrisisCleanupShareLocationRepository
import com.crisiscleanup.core.data.repository.CrisisCleanupTeamsRepository
import com.crisiscleanup.core.data.repository.CrisisCleanupWorkTypeStatusRepository
import com.crisiscleanup.core.data.repository.CrisisCleanupWorksiteChangeRepository
Expand All @@ -56,6 +57,7 @@ import com.crisiscleanup.core.data.repository.OrgVolunteerRepository
import com.crisiscleanup.core.data.repository.OrganizationsRepository
import com.crisiscleanup.core.data.repository.RequestRedeployRepository
import com.crisiscleanup.core.data.repository.SearchWorksitesRepository
import com.crisiscleanup.core.data.repository.ShareLocationRepository
import com.crisiscleanup.core.data.repository.TeamsRepository
import com.crisiscleanup.core.data.repository.UsersRepository
import com.crisiscleanup.core.data.repository.WorkTypeStatusRepository
Expand Down Expand Up @@ -210,6 +212,11 @@ interface DataModule {

@Binds
fun bindsTeamsRepository(repository: CrisisCleanupTeamsRepository): TeamsRepository

@Binds
fun bindsShareLocationRepository(
repository: CrisisCleanupShareLocationRepository,
): ShareLocationRepository
}

@Module
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,8 @@ class AppPreferencesRepository @Inject constructor(
override suspend fun setAnalytics(allowAll: Boolean) {
preferencesDataSource.setAnalytics(allowAll)
}

override suspend fun setShareLocationWithOrg(share: Boolean) {
preferencesDataSource.setShareLocationWithOrg(share)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,19 @@ interface IncidentsRepository {
*/
val incidents: Flow<List<Incident>>

/**
* Stream of [Incident]s with active phone numbers
*/
val hotlineIncidents: Flow<List<Incident>>

suspend fun getIncident(id: Long, loadFormFields: Boolean = false): Incident?
suspend fun getIncidents(startAt: Instant): List<Incident>
suspend fun getIncidentsList(): List<IncidentIdNameType>

fun streamIncident(id: Long): Flow<Incident?>

suspend fun pullIncidents()
suspend fun pullHotlineIncidents()

suspend fun pullIncident(id: Long)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,6 @@ interface LocalAppPreferencesRepository {
suspend fun setTableViewSortBy(sortBy: WorksiteSortBy)

suspend fun setAnalytics(allowAll: Boolean)

suspend fun setShareLocationWithOrg(share: Boolean)
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ class OfflineFirstIncidentsRepository @Inject constructor(
override val incidents: Flow<List<Incident>> =
incidentDao.streamIncidents().mapLatest { it.map(PopulatedIncident::asExternalModel) }

override val hotlineIncidents = incidents.mapLatest {
it.filter { incident ->
incident.activePhoneNumbers.isNotEmpty()
}
}

override suspend fun getIncident(id: Long, loadFormFields: Boolean) =
withContext(ioDispatcher) {
if (loadFormFields) {
Expand Down Expand Up @@ -193,6 +199,22 @@ class OfflineFirstIncidentsRepository @Inject constructor(
}
}

override suspend fun pullHotlineIncidents() {
try {
val hotlineIncidents = networkDataSource
.getIncidentsNoAuth(
incidentsQueryFields,
after = Clock.System.now() - 120.days,
)
.filter { it.activePhoneNumber?.isNotEmpty() == true }
if (hotlineIncidents.isNotEmpty()) {
saveIncidentsPrimaryData(hotlineIncidents)
}
} catch (e: Exception) {
logger.logDebug(e)
}
}

override suspend fun pullIncident(id: Long) {
val networkIncident = networkDataSource.getIncident(id, fullIncidentQueryFields)
networkIncident?.let { incident ->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.crisiscleanup.core.data.repository

import com.crisiscleanup.core.common.LocationProvider
import com.crisiscleanup.core.common.log.AppLogger
import com.crisiscleanup.core.common.log.CrisisCleanupLoggers
import com.crisiscleanup.core.common.log.Logger
import com.crisiscleanup.core.network.CrisisCleanupWriteApi
import kotlinx.coroutines.flow.first
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import java.util.concurrent.atomic.AtomicReference
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.time.Duration.Companion.minutes

interface ShareLocationRepository {
suspend fun shareLocation()
}

@Singleton
class CrisisCleanupShareLocationRepository @Inject
constructor(
private val accountDataRepository: AccountDataRepository,
private val appPreferencesRepository: LocalAppPreferencesRepository,
private val locationProvider: LocationProvider,
private val writeApiClient: CrisisCleanupWriteApi,
@Logger(CrisisCleanupLoggers.App) private val logger: AppLogger,
) : ShareLocationRepository {

private var shareTimestamp = AtomicReference(Instant.fromEpochSeconds(0))
private val shareInterval = 1.minutes

override suspend fun shareLocation() {
val shareLocationWithOrg =
appPreferencesRepository.userPreferences.first().shareLocationWithOrg
val areTokensValid = accountDataRepository.accountData.first().areTokensValid
if (shareLocationWithOrg &&
areTokensValid
) {
locationProvider.getLocation()?.let { location ->
synchronized(shareTimestamp) {
val now = Clock.System.now()
if (shareTimestamp.get() + shareInterval > now) {
return
}
shareTimestamp.set(now)
}

try {
writeApiClient.shareLocation(location.first, location.second)
} catch (e: Exception) {
logger.logException(e)
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ message UserPreferences {

bool hide_getting_started_video = 10;
bool is_menu_tutorial_done = 11;

bool share_location_with_org = 12;
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class LocalAppPreferencesDataSource @Inject constructor(
hideGettingStartedVideo = it.hideGettingStartedVideo,

isMenuTutorialDone = it.isMenuTutorialDone,

shareLocationWithOrg = it.shareLocationWithOrg,
)
}

Expand Down Expand Up @@ -157,4 +159,11 @@ class LocalAppPreferencesDataSource @Inject constructor(
it.copy { isMenuTutorialDone = isDone }
}
}


suspend fun setShareLocationWithOrg(share: Boolean) {
userPreferences.updateData {
it.copy { shareLocationWithOrg = share }
}
}
}
1 change: 1 addition & 0 deletions core/designsystem/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ dependencies {
implementation(projects.core.common)

implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtimeCompose)
api(libs.androidx.compose.foundation)
api(libs.androidx.compose.foundation.layout)
api(libs.androidx.compose.material.iconsExtended)
Expand Down
Loading

0 comments on commit 26ff95c

Please sign in to comment.