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
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ interface AppSettings {

val lastTransferType: TransferType
val lastAuthorEmail: String?
val idOfAccountWithGuestData: Long?
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class SwissTransferInjection(
private val environment: ApiEnvironment,
private val userAgent: String,
private val legacyDatabaseRootDirectory: String? = null,
private val databaseNameOrPath: String? = null,
private val databaseNameOrPath: String,
private val crashReport: CrashReportInterface,
) {

Expand All @@ -81,7 +81,7 @@ class SwissTransferInjection(

private val realmProvider by lazy { RealmProvider(legacyDatabaseRootDirectory) }
private val appDatabase by lazy {
val databaseConfig = DatabaseConfig(databaseNameOrPath = databaseNameOrPath ?: "")
val databaseConfig = DatabaseConfig(databaseNameOrPath = databaseNameOrPath)
DatabaseProvider(databaseConfig).getAppDatabase()
}
private val apiClientProvider by lazy { ApiClientProvider(userAgent, crashReport) }
Expand Down Expand Up @@ -125,6 +125,7 @@ class SwissTransferInjection(
appDatabase = appDatabase,
uploadController = uploadController,
transferController = transferController,
appSettingsManager = appSettingsManager,
realmProvider = realmProvider,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@file:OptIn(ExperimentalCoroutinesApi::class)

package com.infomaniak.multiplatform_swisstransfer.managers

import com.infomaniak.multiplatform_swisstransfer.common.exceptions.RealmException
Expand All @@ -23,6 +25,15 @@ import com.infomaniak.multiplatform_swisstransfer.database.AppDatabase
import com.infomaniak.multiplatform_swisstransfer.database.RealmProvider
import com.infomaniak.multiplatform_swisstransfer.database.controllers.TransferController
import com.infomaniak.multiplatform_swisstransfer.database.controllers.UploadController
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.transformLatest
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlin.coroutines.cancellation.CancellationException
Expand All @@ -39,15 +50,35 @@ class AccountManager internal constructor(
private val appDatabase: AppDatabase,
private val uploadController: UploadController,
private val transferController: TransferController,
private val appSettingsManager: AppSettingsManager,
private val realmProvider: RealmProvider,
) {

private val userSwitchMutex = Mutex()

private val _currentUserFlow = MutableStateFlow<STUser?>(value = null)
val currentUserFlow: StateFlow<STUser?> = _currentUserFlow.asStateFlow()

// We cache the current user to avoid creating database instances when it's the same user
var currentUser: STUser? = null
var currentUser: STUser? by _currentUserFlow::value
private set

val showGuestData: Flow<Boolean> = currentUserFlow.transformLatest { currentUser ->
when (currentUser) {
STUser.GuestUser -> emit(true)
is STUser.AuthUser -> emitAll(appSettingsManager.appSettings.map { appSettings ->
appSettings?.idOfAccountWithGuestData == currentUser.id
})
null -> emit(false)
}
}.distinctUntilChanged()

fun shouldShowGuestData(targetUser: STUser.AuthUser): Flow<Boolean> {
return appSettingsManager.appSettings.map { appSettings ->
appSettings?.idOfAccountWithGuestData == targetUser.id
}
}

val shouldUseV1Api: Boolean get() = currentUser is STUser.GuestUser

/**
Expand All @@ -56,6 +87,10 @@ class AccountManager internal constructor(
@Throws(RealmException::class, CancellationException::class)
suspend fun loadUser(user: STUser) {
userSwitchMutex.withLock {
val authenticatedUser = (currentUser as? STUser.AuthUser)
if (authenticatedUser != null) {
appSettingsManager.updateLinkGuestToAccountIfNeeded(accountId = authenticatedUser.id)
}
if (currentUser?.id != user.id) loadDatabase(user)
currentUser = user
}
Expand All @@ -77,6 +112,9 @@ class AccountManager internal constructor(
}
userSwitchMutex.withLock {
currentUser = newSTUser
if (newSTUser !is STUser.AuthUser) {
appSettingsManager.updateLinkGuestToAccountIfNeeded(accountId = null)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@

package com.infomaniak.multiplatform_swisstransfer.managers

import com.infomaniak.multiplatform_swisstransfer.common.exceptions.RealmException
import androidx.room.immediateTransaction
import androidx.room.useWriterConnection
import com.infomaniak.multiplatform_swisstransfer.common.interfaces.appSettings.AppSettings
import com.infomaniak.multiplatform_swisstransfer.common.models.DownloadLimit
import com.infomaniak.multiplatform_swisstransfer.common.models.EmailLanguage
Expand All @@ -32,14 +33,12 @@ import com.infomaniak.multiplatform_swisstransfer.database.controllers.AppSettin
import com.infomaniak.multiplatform_swisstransfer.database.dao.AppSettingsDao
import com.infomaniak.multiplatform_swisstransfer.database.models.appSettings.v2.AppSettingsDB
import com.infomaniak.multiplatform_swisstransfer.utils.EmailLanguageUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.transformLatest
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import kotlin.coroutines.cancellation.CancellationException

/**
Expand All @@ -54,11 +53,8 @@ class AppSettingsManager internal constructor(
private val emailLanguageUtils: EmailLanguageUtils,
) {

private val dao get() = appDatabase.getAppSettingsDao()
private val dao: AppSettingsDao get() = appDatabase.getAppSettingsDao()

/**
* A [Flow] that emits the current [AppSettings] object whenever it changes.
*/
/**
* A [Flow] that emits the current [AppSettings] object whenever it changes.
*/
Expand Down Expand Up @@ -141,6 +137,26 @@ class AppSettingsManager internal constructor(
dao.updateLastAuthorEmail(authorEmail)
}

/**
* Sets which account will be able to see guest data too.
* It's designed to be the first logged-in account.
*
* This link can be removed when no accounts
*/
internal suspend fun updateLinkGuestToAccountIfNeeded(accountId: Long?) {
appDatabase.useWriterConnection {
it.immediateTransaction {
val currentlyLinkedAccountId = dao.idOfAccountWithGuestData()
if (currentlyLinkedAccountId == accountId) return@immediateTransaction // Nothing to do.
val notLinkedYet = currentlyLinkedAccountId == null
val linkRemoval = accountId == null
if (notLinkedYet || linkRemoval) { // Don't break existing link.
dao.updateIdOfAccountWithGuestData(accountId)
}
}
}
}

private object Migrator {
private val mutex = Mutex()

Expand All @@ -151,6 +167,7 @@ class AppSettingsManager internal constructor(
emailLanguageUtils: EmailLanguageUtils
) {
mutex.withLock {
//TODO[Nit]: Is not an actual migration (it's only one of the 2 cases). Also, could be a DB transaction.
val hasMigrated = dao.getAppSettings().first() != null
if (hasMigrated) return
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@file:OptIn(ExperimentalCoroutinesApi::class)

package com.infomaniak.multiplatform_swisstransfer.managers

import com.infomaniak.multiplatform_swisstransfer.common.interfaces.ui.FileUi
Expand All @@ -23,8 +25,11 @@ import com.infomaniak.multiplatform_swisstransfer.data.STUser
import com.infomaniak.multiplatform_swisstransfer.database.AppDatabase
import com.infomaniak.multiplatform_swisstransfer.database.controllers.FileController
import com.infomaniak.multiplatform_swisstransfer.mappers.toFileUiList
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.transformLatest

class FileManager(
private val accountManager: AccountManager,
Expand All @@ -38,10 +43,20 @@ class FileManager(
* @param folderUuid The UUID of the folder within the transfer.
* @return A flow of lists of [FileUi] objects representing the files in the transfer.
*/
fun getFilesFromTransfer(folderUuid: String): Flow<List<FileUi>> {
if (accountManager.currentUser is STUser.AuthUser) {
return appDatabase.getTransferDao().filesByFolderIdFlow(folderId = folderUuid).map { it.toFileUiList() }
fun getFilesFromTransfer(
folderUuid: String
): Flow<List<FileUi>> = accountManager.currentUserFlow.transformLatest { currentUser ->
when (currentUser) {
is STUser.AuthUser -> {
emitAll(appDatabase.getTransferDao().filesByFolderIdFlow(folderId = folderUuid).map { it.toFileUiList() })
}
else -> emit(emptyList())
}
}.transformLatest { files ->
if (files.isEmpty()) {
emitAll(fileController.getFilesFromTransfer(folderUuid).map { files -> files.mapToList { FileUi(it) } })
} else {
emit(files)
}
return fileController.getFilesFromTransfer(folderUuid).map { files -> files.mapToList { FileUi(it) } }
}
}
Loading