Skip to content
Merged
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
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 = 264
val buildVersion = 268
applicationId = "com.crisiscleanup"
versionCode = buildVersion
versionName = "0.9.${buildVersion - 168}"
Expand Down
8 changes: 3 additions & 5 deletions app/src/main/java/com/crisiscleanup/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.crisiscleanup

import android.content.Intent
import android.graphics.Color
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.SystemBarStyle
Expand All @@ -15,7 +16,6 @@ import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.toArgb
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
Expand All @@ -38,7 +38,6 @@ import com.crisiscleanup.core.data.repository.EndOfLifeRepository
import com.crisiscleanup.core.data.repository.LanguageTranslationsRepository
import com.crisiscleanup.core.data.repository.LocalAppMetricsRepository
import com.crisiscleanup.core.designsystem.theme.CrisisCleanupTheme
import com.crisiscleanup.core.designsystem.theme.navigationContainerColor
import com.crisiscleanup.core.model.data.DarkThemeConfig
import com.crisiscleanup.sync.initializers.scheduleSyncWorksites
import com.crisiscleanup.ui.CrisisCleanupApp
Expand Down Expand Up @@ -127,10 +126,9 @@ class MainActivity : ComponentActivity() {
windowSizeClass = windowSizeClass,
)

val barColor = navigationContainerColor.toArgb()
enableEdgeToEdge(
statusBarStyle = SystemBarStyle.dark(barColor),
navigationBarStyle = SystemBarStyle.dark(barColor),
statusBarStyle = SystemBarStyle.dark(Color.TRANSPARENT),
navigationBarStyle = SystemBarStyle.dark(Color.TRANSPARENT),
)

CompositionLocalProvider {
Expand Down
7 changes: 5 additions & 2 deletions app/src/main/java/com/crisiscleanup/MainActivityViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.crisiscleanup.core.common.log.Logger
import com.crisiscleanup.core.common.network.CrisisCleanupDispatchers.IO
import com.crisiscleanup.core.common.network.Dispatcher
import com.crisiscleanup.core.common.sync.SyncPuller
import com.crisiscleanup.core.common.sync.SyncPusher
import com.crisiscleanup.core.common.throttleLatest
import com.crisiscleanup.core.data.IncidentSelector
import com.crisiscleanup.core.data.repository.AccountDataRefresher
Expand Down Expand Up @@ -67,6 +68,7 @@ class MainActivityViewModel @Inject constructor(
val tutorialViewTracker: TutorialViewTracker,
val translator: KeyResourceTranslator,
private val syncPuller: SyncPuller,
private val syncPusher: SyncPusher,
appSettingsProvider: AppSettingsProvider,
private val appEnv: AppEnv,
firebaseAnalytics: FirebaseAnalytics,
Expand Down Expand Up @@ -205,6 +207,8 @@ class MainActivityViewModel @Inject constructor(
syncPuller.appPullLanguage()
syncPuller.appPullStatuses()

syncPusher.scheduleSyncMedia()

accountDataRepository.accountData
.mapLatest { it.hasAcceptedTerms }
.filter { !it }
Expand Down Expand Up @@ -263,10 +267,9 @@ class MainActivityViewModel @Inject constructor(
return
}

if (isUpdatingTermsAcceptance.value) {
if (!isUpdatingTermsAcceptance.compareAndSet(expect = false, update = true)) {
return
}
isUpdatingTermsAcceptance.value = true
viewModelScope.launch(ioDispatcher) {
try {
val isAccepted = accountUpdateRepository.acceptTerms()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ fun CrisisCleanupAuthNavHost(
navController.navigateToLoginWithPhone()
}
}
val navToLogin = navController::popToAuth
val navToForgotPasswordClearStack = remember(navController) {
{
navController.popToAuth()
navController.navigateToForgotPassword()
}
}

NavHost(
navController = navController,
Expand Down Expand Up @@ -110,8 +117,11 @@ fun CrisisCleanupAuthNavHost(
closeAuthentication = closeAuthentication,
)
requestAccessScreen(
false,
onBack = onBack,
closeRequestAccess = navToLoginWithEmail,
openAuth = navToAuth,
openForgotPassword = navToForgotPasswordClearStack,
)
orgPersistentInviteScreen(
onBack = onBack,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.crisiscleanup.core.appnav.navigateToExistingCase
import com.crisiscleanup.core.data.model.ExistingWorksiteIdentifier
import com.crisiscleanup.core.model.data.EmptyIncident
import com.crisiscleanup.core.model.data.EmptyWorksite
import com.crisiscleanup.feature.authentication.navigation.requestAccessScreen
import com.crisiscleanup.feature.authentication.navigation.resetPasswordScreen
import com.crisiscleanup.feature.caseeditor.navigation.caseAddFlagScreen
import com.crisiscleanup.feature.caseeditor.navigation.caseEditMoveLocationOnMapScreen
Expand Down Expand Up @@ -246,5 +247,13 @@ fun CrisisCleanupNavHost(
onBack = onBack,
closeResetPassword = onBack,
)

requestAccessScreen(
true,
onBack = onBack,
closeRequestAccess = onBack,
openAuth = {},
openForgotPassword = {},
)
}
}
10 changes: 5 additions & 5 deletions app/src/main/java/com/crisiscleanup/ui/AppNavigation.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ 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.graphics.vector.ImageVector
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
Expand All @@ -42,17 +41,18 @@ private fun TopLevelDestination.Icon(isSelected: Boolean, description: String) {
} else {
unselectedIcon
}
var tint = LocalContentColor.current
if (!isSelected) {
tint = tint.disabledAlpha()
}
when (icon) {
is Icon.ImageVectorIcon -> Icon(
imageVector = icon.imageVector,
contentDescription = description,
tint = tint,
)

is Icon.DrawableResourceIcon -> {
var tint = LocalContentColor.current
if (isSelected) {
tint = Color.White
}
Icon(
painter = painterResource(id = icon.id),
contentDescription = description,
Expand Down
49 changes: 32 additions & 17 deletions app/src/main/java/com/crisiscleanup/ui/CrisisCleanupApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.slideIn
import androidx.compose.animation.slideOut
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
Expand Down Expand Up @@ -58,6 +59,7 @@ import com.crisiscleanup.core.designsystem.component.CrisisCleanupAlertDialog
import com.crisiscleanup.core.designsystem.component.CrisisCleanupBackground
import com.crisiscleanup.core.designsystem.component.CrisisCleanupTextButton
import com.crisiscleanup.core.designsystem.theme.LocalDimensions
import com.crisiscleanup.core.designsystem.theme.navigationContainerColor
import com.crisiscleanup.core.model.data.TutorialViewId
import com.crisiscleanup.core.ui.AppLayoutArea
import com.crisiscleanup.core.ui.LayoutSizePosition
Expand Down Expand Up @@ -142,6 +144,8 @@ private fun BoxScope.LoadedContent(
var openAuthentication by rememberSaveable { mutableStateOf(isNotAuthenticatedState) }

val showPasswordReset by viewModel.showPasswordReset.collectAsStateWithLifecycle(false)
val orgUserInviteCode by viewModel.orgUserInvites.collectAsStateWithLifecycle("")
val showOrgInviteTransfer = orgUserInviteCode.isNotBlank()

if (openAuthentication ||
isNotAuthenticatedState
Expand All @@ -158,19 +162,22 @@ private fun BoxScope.LoadedContent(

if (isNotAuthenticatedState) {
val showMagicLinkLogin by viewModel.showMagicLinkLogin.collectAsStateWithLifecycle(false)
val orgUserInviteCode by viewModel.orgUserInvites.collectAsStateWithLifecycle("")
val orgPersistentInvite by viewModel.orgPersistentInvites.collectAsStateWithLifecycle()

if (showPasswordReset) {
LaunchedEffect(Unit) {
appState.navController.navigateToPasswordReset(false)
with(appState.navController) {
if (showPasswordReset) {
LaunchedEffect(Unit) {
navigateToPasswordReset(false)
}
} else if (showMagicLinkLogin) {
navigateToMagicLinkLogin()
} else if (showOrgInviteTransfer) {
LaunchedEffect(Unit) {
navigateToRequestAccess(orgUserInviteCode, false)
}
} else if (orgPersistentInvite.isValidInvite) {
navigateToOrgPersistentInvite()
}
} else if (showMagicLinkLogin) {
appState.navController.navigateToMagicLinkLogin()
} else if (orgUserInviteCode.isNotBlank()) {
appState.navController.navigateToRequestAccess(orgUserInviteCode)
} else if (orgPersistentInvite.isValidInvite) {
appState.navController.navigateToOrgPersistentInvite()
}
}
} else if (!hasAcceptedTerms) {
Expand Down Expand Up @@ -225,9 +232,15 @@ private fun BoxScope.LoadedContent(
}
}

if (showPasswordReset) {
LaunchedEffect(Unit) {
appState.navController.navigateToPasswordReset(true)
with(appState.navController) {
if (showPasswordReset) {
LaunchedEffect(Unit) {
navigateToPasswordReset(true)
}
} else if (showOrgInviteTransfer) {
LaunchedEffect(Unit) {
navigateToRequestAccess(orgUserInviteCode, true)
}
}
}
}
Expand Down Expand Up @@ -340,9 +353,11 @@ private fun NavigableContent(
}

Scaffold(
modifier = Modifier.semantics {
testTagsAsResourceId = true
},
modifier = Modifier
.background(navigationContainerColor)
.semantics {
testTagsAsResourceId = true
},
containerColor = Color.Transparent,
contentColor = MaterialTheme.colorScheme.onBackground,
contentWindowInsets = WindowInsets(0, 0, 0, 0),
Expand Down Expand Up @@ -396,7 +411,7 @@ private fun NavigableContent(
}

val isKeyboardOpen = rememberIsKeyboardOpen()
Column {
Column(Modifier.background(Color.White)) {
val snackbarAreaHeight =
if (!showNavigation &&
snackbarHostState.currentSnackbarData != null &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinBaseExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension

internal const val DefaultConfigTargetSdk = 35
internal const val DefaultConfigTargetSdk = 36

/**
* Configure base Kotlin with Android options
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ object RouteConstant {
const val AUTH_RESET_PASSWORD_ROUTE = "$AUTH_ROUTE/auth_reset_password_route"
const val MAGIC_LINK_ROUTE = "$AUTH_ROUTE/magic_link_login"

const val REQUEST_ACCESS_ROUTE = "$AUTH_ROUTE/request_access"
const val AUTH_REQUEST_ACCESS_ROUTE = "$AUTH_ROUTE/request_access"
const val ORG_PERSISTENT_INVITE_ROUTE = "$AUTH_ROUTE/org_persistent_invite"

const val VOLUNTEER_ORG_ROUTE = "$AUTH_ROUTE/volunteer_org"
Expand Down Expand Up @@ -51,6 +51,7 @@ object RouteConstant {
const val WORKSITE_IMAGES_ROUTE = "worksite_images"

const val ACCOUNT_RESET_PASSWORD_ROUTE = "account_reset_password_route"
const val ACCOUNT_TRANSFER_ORG_ROUTE = "account_transfer_org"

const val LISTS_ROUTE = "crisis_cleanup_lists"
const val VIEW_LIST_ROUTE = "view_list"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ interface AccountUpdateRepository {
suspend fun initiatePasswordReset(emailAddress: String): PasswordResetInitiation
suspend fun changePassword(password: String, token: String): Boolean
suspend fun acceptTerms(): Boolean
suspend fun acceptOrganizationChange(
action: ChangeOrganizationAction,
invitationToken: String,
): Boolean
}

class CrisisCleanupAccountUpdateRepository @Inject constructor(
Expand Down Expand Up @@ -75,4 +79,21 @@ class CrisisCleanupAccountUpdateRepository @Inject constructor(
}
return false
}

override suspend fun acceptOrganizationChange(
action: ChangeOrganizationAction,
invitationToken: String,
): Boolean {
try {
return accountApi.moveToOrganization(action.literal, invitationToken)
} catch (e: Exception) {
logger.logException(e)
}
return false
}
}

enum class ChangeOrganizationAction(val literal: String) {
All("all"),
Users("users"),
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,8 @@ class AppPreferencesRepository @Inject constructor(
override suspend fun setWorkScreenView(isTableView: Boolean) {
preferencesDataSource.saveWorkScreenView(isTableView)
}

override suspend fun setSyncMediaImmediate(syncImmediate: Boolean) {
preferencesDataSource.saveSyncMediaImmediate(syncImmediate)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.datetime.Clock
import javax.inject.Inject
import javax.inject.Singleton
Expand All @@ -25,7 +25,7 @@ interface CasesFilterRepository {
val casesFiltersLocation: StateFlow<Triple<CasesFilter, Boolean, Long>>
val filtersCount: Flow<Int>

fun changeFilters(filters: CasesFilter)
suspend fun changeFilters(filters: CasesFilter)
fun updateWorkTypeFilters(workTypes: Collection<String>)
fun reapplyFilters()
}
Expand Down Expand Up @@ -60,10 +60,8 @@ class CrisisCleanupCasesFilterRepository @Inject constructor(

// TODO Update or clear work type filters when incident changes

override fun changeFilters(filters: CasesFilter) {
externalScope.launch(ioDispatcher) {
dataSource.updateFilters(filters)
}
override suspend fun changeFilters(filters: CasesFilter) = withContext(ioDispatcher) {
dataSource.updateFilters(filters)
}

override fun updateWorkTypeFilters(workTypes: Collection<String>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,6 @@ interface LocalAppPreferencesRepository {
suspend fun setTeamMapBounds(bounds: IncidentCoordinateBounds)

suspend fun setWorkScreenView(isTableView: Boolean)

suspend fun setSyncMediaImmediate(syncImmediate: Boolean)
}
Loading
Loading