Skip to content

Commit

Permalink
Merge pull request #417 from Assocify-Team/ft/AssoImage
Browse files Browse the repository at this point in the history
Current association Image
  • Loading branch information
zizouet authored Jun 2, 2024
2 parents 91f8ceb + 22fc748 commit 02429b4
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.github.se.assocify.screens

import android.net.Uri
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.assertIsSelected
Expand All @@ -14,6 +15,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import com.github.se.assocify.model.CurrentUser
import com.github.se.assocify.model.database.AccountingCategoryAPI
import com.github.se.assocify.model.database.AccountingSubCategoryAPI
import com.github.se.assocify.model.database.AssociationAPI
import com.github.se.assocify.model.database.BalanceAPI
import com.github.se.assocify.model.database.BudgetAPI
import com.github.se.assocify.model.database.ReceiptAPI
Expand Down Expand Up @@ -46,7 +48,7 @@ class TreasuryScreenTest : TestCase(kaspressoBuilder = Kaspresso.Builder.withCom
@get:Rule val composeTestRule = createComposeRule()
@get:Rule val mockkRule = MockKRule(this)
private val navActions =
mockk<NavigationActions>() {
mockk<NavigationActions> {
every { navigateToMainTab(any()) } answers { tabSelected = true }
every { navigateTo(any()) } answers {}
}
Expand Down Expand Up @@ -139,6 +141,14 @@ class TreasuryScreenTest : TestCase(kaspressoBuilder = Kaspresso.Builder.withCom
onSuccessCallback(PermissionRole("roleUid", "testAssociation", RoleType.TREASURY))
}
}
private val mockAssocAPI =
mockk<AssociationAPI>() {
every { getLogo(any(), any(), any()) } answers
{
val onSuccessCallback = secondArg<(Uri) -> Unit>()
onSuccessCallback(mockk())
}
}

@Before
fun testSetup() {
Expand All @@ -152,7 +162,8 @@ class TreasuryScreenTest : TestCase(kaspressoBuilder = Kaspresso.Builder.withCom
mockAccountingSubCategoryAPI,
mockBalanceAPI,
mockBudgetAPI,
mockUserAPI)
mockUserAPI,
mockAssocAPI)
composeTestRule.setContent { TreasuryScreen(navActions, treasuryViewModel) }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class ProfileScreenTest : TestCase(kaspressoBuilder = Kaspresso.Builder.withComp
private val asso1 = Association("asso", "test", "test", LocalDate.EPOCH)
private val asso2 = Association("asso2", "test2", "test2", LocalDate.EPOCH)
private val mockAssocAPI =
mockk<AssociationAPI>() {
mockk<AssociationAPI> {
every { getAssociation("asso", any(), any()) } answers
{
val onSuccessCallback = secondArg<(Association) -> Unit>()
Expand All @@ -62,6 +62,7 @@ class ProfileScreenTest : TestCase(kaspressoBuilder = Kaspresso.Builder.withComp
val onSuccessCallback = secondArg<(Association) -> Unit>()
onSuccessCallback(asso2)
}
every { getLogo(any(), any(), any()) } answers {}
}
private val mockUserAPI =
mockk<UserAPI>() {
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/java/com/github/se/assocify/model/CurrentUser.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
package com.github.se.assocify.model

import android.net.Uri
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow

object CurrentUser {
var userUid: String? = null
var associationUid: String? = null
private var _associationLogo: StateFlow<Uri?> = MutableStateFlow(null)
val associationLogo: StateFlow<Uri?> = _associationLogo

fun setAssociationLogo(uri: Uri?) {
(_associationLogo as MutableStateFlow).value = uri
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.github.se.assocify.model.database

import android.net.Uri
import android.util.Log
import com.github.se.assocify.model.CurrentUser
import com.github.se.assocify.model.entities.Association
import com.github.se.assocify.model.entities.AssociationMember
import com.github.se.assocify.model.entities.PermissionRole
Expand All @@ -25,9 +27,11 @@ import kotlinx.serialization.json.JsonObject
class AssociationAPI(private val db: SupabaseClient, cachePath: Path) : SupabaseApi() {
private var associationCache = mapOf<String, Association>()
private val imageCacher = ImageCacher(60 * 60_000, cachePath, db.storage["association"])
private var currentAssociationCache: String? = null

init {
updateCache({}, {}) // Try and fill the cache as quickly as possible
currentAssociationCache = CurrentUser.associationUid
}

/**
Expand All @@ -41,6 +45,7 @@ class AssociationAPI(private val db: SupabaseClient, cachePath: Path) : Supabase
val assoc = db.from("association").select().decodeList<SupabaseAssociation>()
associationCache = assoc.associateBy { it.uid!! }.mapValues { it.value.toAssociation() }
memberCache = null
currentAssociationCache = CurrentUser.associationUid
onSuccess(associationCache)
}
}
Expand Down Expand Up @@ -436,8 +441,12 @@ class AssociationAPI(private val db: SupabaseClient, cachePath: Path) : Supabase
* @param onSuccess called on success with the URI of the logo
* @param onFailure called on failure
*/
fun getLogo(associationId: String, onSuccess: (Uri) -> Unit, onFailure: (Exception) -> Unit) {
imageCacher.fetchImage(associationId, { onSuccess(Uri.fromFile(it.toFile())) }, onFailure)
fun getLogo(associationId: String, onSuccess: (Uri?) -> Unit, onFailure: (Exception) -> Unit) {
Log.d("image", "getLogo from association $associationId")
if (associationId != currentAssociationCache) {
currentAssociationCache = associationId
imageCacher.fetchImage(associationId, { onSuccess(Uri.fromFile(it.toFile())) }, onFailure)
}
}

@Serializable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class ImageCacher(val timeout: Long, val cacheDir: Path, private val bucket: Buc
if (!renamed) {
Log.w("IMG", "Failed to rename temporary image cache file ($pathInBucket)")
}

onSuccess(imageFile)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ fun NavGraphBuilder.mainNavGraph(
receiptsAPI,
accountingCategoriesAPI,
accountingSubCategoryAPI,
userAPI)
userAPI,
associationAPI)
eventGraph(navActions, eventAPI, taskAPI)
profileGraph(
navActions,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,37 @@
package com.github.se.assocify.ui.composables

import android.util.Log
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.AccountCircle
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.outlined.AccountCircle
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.SearchBar
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import com.github.se.assocify.model.CurrentUser

/**
* Main tab top bar
Expand Down Expand Up @@ -49,6 +60,9 @@ fun MainTopBar(
// Page state
var currentPage by remember { mutableIntStateOf(page) }

val associationLogoUri = CurrentUser.associationLogo.collectAsState()
val associationLogoUriValue = associationLogoUri.value

if (currentPage != page) {
currentPage = page
searchBarVisible = false
Expand All @@ -60,9 +74,25 @@ fun MainTopBar(
title = { Text(text = title) },
navigationIcon = {
IconButton(modifier = Modifier.testTag("accountIconButton"), onClick = {}) {
Icon(
imageVector = Icons.Filled.AccountCircle,
contentDescription = "Association Account")
// profile picture
if (associationLogoUriValue != null) {
Log.d("image", "CurrentUser.associationLogo: ${associationLogoUriValue}")
AsyncImage(
modifier =
Modifier.size(80.dp)
.clip(CircleShape) // Clip the image to a circle shape
.aspectRatio(1f)
.testTag("profilePicture"),
model = associationLogoUriValue,
contentDescription = "profile picture",
contentScale = ContentScale.Crop)
} else {
Log.d("image", "CurrentUser.associationLogo: ${associationLogoUriValue}")
Icon(
modifier = Modifier.fillMaxSize(),
imageVector = Icons.Outlined.AccountCircle,
contentDescription = "default profile icon")
}
}
},
actions = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ class ProfileViewModel(
}
val oldAssociationUid = CurrentUser.associationUid
CurrentUser.associationUid = association.uid
assoAPI.getLogo(
CurrentUser.associationUid!!,
{ uri -> CurrentUser.setAssociationLogo(uri) },
{ CurrentUser.setAssociationLogo(null) })
userAPI.getCurrentUserRole(
{ role ->
_uiState.value = _uiState.value.copy(selectedAssociation = association)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable
import com.github.se.assocify.model.database.AccountingCategoryAPI
import com.github.se.assocify.model.database.AccountingSubCategoryAPI
import com.github.se.assocify.model.database.AssociationAPI
import com.github.se.assocify.model.database.BalanceAPI
import com.github.se.assocify.model.database.BudgetAPI
import com.github.se.assocify.model.database.ReceiptAPI
Expand All @@ -22,7 +23,8 @@ fun NavGraphBuilder.treasuryGraph(
receiptsAPI: ReceiptAPI,
accountingCategoryAPI: AccountingCategoryAPI,
accountingSubCategoryAPI: AccountingSubCategoryAPI,
userAPI: UserAPI
userAPI: UserAPI,
associationAPI: AssociationAPI
) {

composable(
Expand All @@ -36,7 +38,8 @@ fun NavGraphBuilder.treasuryGraph(
accountingSubCategoryAPI,
balanceAPI,
budgetAPI,
userAPI)
userAPI,
associationAPI)
}
TreasuryScreen(navigationActions, treasuryViewModel)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.github.se.assocify.ui.screens.treasury

import android.util.Log
import androidx.compose.material3.SnackbarHostState
import com.github.se.assocify.model.CurrentUser
import com.github.se.assocify.model.database.AccountingCategoryAPI
import com.github.se.assocify.model.database.AccountingSubCategoryAPI
import com.github.se.assocify.model.database.AssociationAPI
import com.github.se.assocify.model.database.BalanceAPI
import com.github.se.assocify.model.database.BudgetAPI
import com.github.se.assocify.model.database.ReceiptAPI
Expand All @@ -21,8 +24,19 @@ class TreasuryViewModel(
accountingSubCategoryAPI: AccountingSubCategoryAPI,
balanceAPI: BalanceAPI,
budgetAPI: BudgetAPI,
userAPI: UserAPI
userAPI: UserAPI,
associationAPI: AssociationAPI
) {
init {
Log.d("image", "getting logo in View model at init")
associationAPI.getLogo(
CurrentUser.associationUid!!,
{ uri ->
Log.d("image", "uri is $uri")
CurrentUser.setAssociationLogo(uri)
},
{ CurrentUser.setAssociationLogo(null) })
}
// ViewModel states
private val _uiState: MutableStateFlow<TreasuryUIState> = MutableStateFlow(TreasuryUIState())
val uiState: StateFlow<TreasuryUIState> = _uiState
Expand Down Expand Up @@ -72,7 +86,7 @@ class TreasuryViewModel(
data class TreasuryUIState(
val snackbarHostState: SnackbarHostState = SnackbarHostState(),
val searchQuery: String = "",
val currentTab: TreasuryPageIndex = TreasuryPageIndex.Receipts
val currentTab: TreasuryPageIndex = TreasuryPageIndex.Receipts,
)

/** Treasury tabs */
Expand Down

0 comments on commit 02429b4

Please sign in to comment.