Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
573d98a
refactor: Fix and simplify AccountUtils and AccountPreferences
LouisCAD Mar 3, 2026
17c5cd8
chore: Update usages of ValidityPeriod
LouisCAD Mar 3, 2026
a6c9707
chore: Update TransferUi constructor calls
LouisCAD Mar 3, 2026
bbfd7d1
chore: Update for new TransferStatus enum entry
LouisCAD Mar 3, 2026
1cef3f6
chore: Ensure pre-prod flavor enables pre-prod for the whole app
LouisCAD Mar 3, 2026
24b8c0c
chore: Forward login issues from the login library to logcat
LouisCAD Mar 3, 2026
07e55fa
chore: Specify databaseNameOrPath for SwissTransferInjection
LouisCAD Mar 3, 2026
bdad1bd
chore: Introduce UploadSessionStarterV1 & TransferUploaderV2
LouisCAD Mar 3, 2026
aae1bd6
chore: Remove workaround for parallel upload
LouisCAD Mar 5, 2026
8514d49
chore: Remove no longer needed commented code
LouisCAD Mar 5, 2026
4379010
chore: Update for download of v2 transfers
LouisCAD Mar 5, 2026
bcf94dc
chore: Add TODO comment regarding duplicated code
LouisCAD Mar 5, 2026
1de30e7
refactor: Only specify preprod in a single place in the code
LunarX Mar 6, 2026
a2f32a1
feat: Hide download all button and download count for v2 transfers
LunarX Mar 6, 2026
a0105b2
refactor: Use mimeType.substringAfterLast directly
sirambd Mar 6, 2026
e612538
refactor: Apply review suggestion
sirambd Mar 6, 2026
607a0ca
refactor: Update the TAG name
sirambd Mar 6, 2026
5e15a2b
feat: Download a transfer with password from api v2
sirambd Mar 6, 2026
ece9411
fix: Fix API v2 password header addition logic
LunarX Mar 6, 2026
8e6d775
refactor: Only specify preprod in a single place in the code (#598)
sirambd Mar 6, 2026
3894071
feat: Download a transfer with password from api v2 (#597)
sirambd Mar 6, 2026
b114808
feat: Hide download all button and download count for v2 transfers (#…
sirambd Mar 6, 2026
680c334
feat: Display the title if available
sirambd Mar 6, 2026
f2138ad
chore: Add transferTitlePlaceholder string res
sirambd Mar 6, 2026
fec38db
feat: Show Api V2 title if available
sirambd Mar 6, 2026
9930181
chore: Update app/src/main/java/com/infomaniak/swisstransfer/ui/previ…
sirambd Mar 6, 2026
9334a8a
chore: Use LocalUser to check if user is in apiV2
sirambd Mar 6, 2026
54ae2a5
refactor: Use spacedBy instead of manually adding spacer everywhere
LunarX Mar 6, 2026
a989b06
fix: Make it so EmailAddressTextField has the same top padding as Out…
LunarX Mar 6, 2026
4ce8587
refactor: Fix preview parameters
LunarX Mar 6, 2026
8d1e3c7
feat: Show Api V2 title if available (#600)
sirambd Mar 6, 2026
61c0567
Refactor pick files screen textfield spacings (#601)
sirambd Mar 6, 2026
354eb60
chore: Use 7.0.0-SNAPSHOT
sirambd Mar 6, 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
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ dependencies {
implementation(core.androidx.work.runtime.ktx)
implementation(core.kotlinx.serialization.json)
implementation(core.splitties.toast)
implementation(core.splitties.preferences)
implementation(core.okhttp)

// Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import android.app.Application
import android.content.Context
import android.util.Log
import androidx.core.app.NotificationManagerCompat
import androidx.work.WorkManager
import com.infomaniak.core.appintegrity.AppIntegrityManager
Expand Down Expand Up @@ -75,9 +76,15 @@
return InfomaniakLogin(
context = appContext,
loginUrl = "${LOGIN_ENDPOINT_URL}/",
appUID = ConfigUtils.safePackage,
appUID = ConfigUtils.safePackage.substringBefore(".preprod"),
clientID = BuildConfig.CLIENT_ID,
accessType = null,
sentryCallback = { message, extras ->
//TODO[Sentry]: Should we forward this to Sentry, or leave it only in logcat for debug?

Check warning on line 83 in app/src/main/java/com/infomaniak/swisstransfer/di/ApplicationModule.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Complete the task associated to this TODO comment.

See more on https://sonarcloud.io/project/issues?id=Infomaniak_android-SwissTransfer&issues=AZy0xgpZ6LiixEtQDUld&open=AZy0xgpZ6LiixEtQDUld&pullRequest=595
val tag = "LoginIssue"
Log.e(tag, message)
Log.e(tag, extras.toString())
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sentryCallback currently logs extras.toString() to logcat. Depending on what extras contains (tokens, user identifiers, URLs), this can leak sensitive information on production devices. Consider guarding this behind BuildConfig.DEBUG, redacting known-sensitive keys/values, or sending a sanitized event to Sentry instead of raw logcat output.

Suggested change
Log.e(tag, extras.toString())
if (BuildConfig.DEBUG) {
Log.e(tag, extras.toString())
}

Copilot uses AI. Check for mistakes.
}
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,25 @@
*/
package com.infomaniak.swisstransfer.di

import com.infomaniak.core.appintegrity.AppIntegrityManager
import com.infomaniak.core.network.ApiEnvironment
import com.infomaniak.multiplatform_swisstransfer.SharedApiUrlCreator
import com.infomaniak.multiplatform_swisstransfer.SwissTransferInjection
import com.infomaniak.multiplatform_swisstransfer.common.utils.ApiEnvironment
import com.infomaniak.multiplatform_swisstransfer.managers.AccountManager
import com.infomaniak.multiplatform_swisstransfer.managers.AppSettingsManager
import com.infomaniak.multiplatform_swisstransfer.managers.FileManager
import com.infomaniak.multiplatform_swisstransfer.managers.InMemoryUploadManager
import com.infomaniak.multiplatform_swisstransfer.managers.TransferManager
import com.infomaniak.swisstransfer.BuildConfig
import com.infomaniak.multiplatform_swisstransfer.managers.UploadV2Manager
import com.infomaniak.swisstransfer.upload.UploadSessionStarter
import com.infomaniak.swisstransfer.upload.UploadSessionStarterV1
import com.infomaniak.swisstransfer.upload.UploadSessionStarterV2
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
import com.infomaniak.multiplatform_swisstransfer.common.utils.ApiEnvironment as KmpApiEnvironement

@Module
@InstallIn(SingletonComponent::class)
Expand All @@ -40,12 +45,29 @@ object SwissTransferInjectionModule {
@Singleton
fun provideSwissTransferInjection(@UserAgent userAgent: String): SwissTransferInjection {
return SwissTransferInjection(
environment = if (BuildConfig.FLAVOR == "preprod") ApiEnvironment.Preprod else ApiEnvironment.Prod,
environment = ApiEnvironment.current.toKmpApiEnvironment(),
userAgent = userAgent,
crashReport = crashReport
crashReport = crashReport,
databaseNameOrPath = "swisstransfer",
)
}

@Provides
fun provideUploadSessionStarter(
sti: SwissTransferInjection,
appIntegrityManager: AppIntegrityManager,
sharedApiUrlCreator: SharedApiUrlCreator,
legacyUploadManager: InMemoryUploadManager,
uploadManager: UploadV2Manager,
): UploadSessionStarter = when {
sti.accountManager.shouldUseV1Api -> UploadSessionStarterV1(
appIntegrityManager = appIntegrityManager,
sharedApiUrlCreator = sharedApiUrlCreator,
uploadManager = legacyUploadManager,
)
else -> UploadSessionStarterV2(uploadManager)
}

@Provides
@Singleton
fun provideTransferManager(sti: SwissTransferInjection): TransferManager = sti.transferManager
Expand All @@ -64,9 +86,21 @@ object SwissTransferInjectionModule {

@Provides
@Singleton
fun provideUploadManager(sti: SwissTransferInjection): InMemoryUploadManager = sti.inMemoryUploadManager
fun provideV1UploadManager(sti: SwissTransferInjection): InMemoryUploadManager = sti.inMemoryUploadManager

@Provides
@Singleton
fun provideUploadManager(sti: SwissTransferInjection): UploadV2Manager = sti.uploadV2Manager

@Provides
@Singleton
fun provideSharedApiUrlCreator(sti: SwissTransferInjection): SharedApiUrlCreator = sti.sharedApiUrlCreator
}

private fun ApiEnvironment.toKmpApiEnvironment(): KmpApiEnvironement {
return when (this) {
ApiEnvironment.PreProd -> KmpApiEnvironement.Preprod
ApiEnvironment.Prod -> KmpApiEnvironement.Prod
is ApiEnvironment.Custom -> error("Custom api environment is not handled by the kmp lib")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@ class LaunchActivity : ComponentActivity() {
@Inject
lateinit var accountUtils: AccountUtils

@Inject
lateinit var accountPreferences: AccountPreferences

@Inject
lateinit var appSettingsManager: AppSettingsManager

Expand Down Expand Up @@ -103,7 +100,7 @@ class LaunchActivity : ComponentActivity() {
private suspend fun connectLoggedOutUser() {
if (!accountUtils.isUserConnected()) {
accountUtils.loginGuestUser()
accountPreferences.isOnboardingDone = true
AccountPreferences().isOnboardingDone = true
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration
import com.infomaniak.core.common.AssociatedUserDataCleanable
import com.infomaniak.core.crossapplogin.back.internal.deviceinfo.DeviceInfoUpdateManager
import com.infomaniak.core.network.ApiEnvironment
import com.infomaniak.core.network.NetworkConfiguration
import com.infomaniak.core.sentry.SentryConfig.configureSentry
import com.infomaniak.multiplatform_swisstransfer.managers.AccountManager
Expand All @@ -45,6 +46,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import splitties.init.injectAsAppCtx
import javax.inject.Inject
import com.infomaniak.multiplatform_swisstransfer.network.exceptions.NetworkException as KmpNetworkException

Expand Down Expand Up @@ -79,6 +81,11 @@ class MainApplication : Application(), Configuration.Provider {
@IoDispatcher
lateinit var ioDispatcher: CoroutineDispatcher

init {
injectAsAppCtx()
configureInfomaniakCore()
}

override val workManagerConfiguration: Configuration
get() = Configuration.Builder().setWorkerFactory(workerFactory).build()

Expand All @@ -87,15 +94,14 @@ class MainApplication : Application(), Configuration.Provider {
override fun onCreate() {
super.onCreate()

configureInfomaniakCore()
configureSentry()

userDataCleanableList = listOf<AssociatedUserDataCleanable>(DeviceInfoUpdateManager)

notificationUtils.initNotificationsChannel()

globalCoroutineScope.launch {
accountUtils.init()
launch { accountUtils.activate() }

launch(ioDispatcher) {
transferManager.getAllTransfers().collectLatest(thumbnailsLocalStorage::cleanExpiredThumbnails)
Expand All @@ -122,6 +128,7 @@ class MainApplication : Application(), Configuration.Provider {
appId = ConfigUtils.safePackage,
appVersionName = BuildConfig.VERSION_NAME,
appVersionCode = BuildConfig.VERSION_CODE,
apiEnvironment = if (BuildConfig.FLAVOR == "preprod") ApiEnvironment.PreProd else ApiEnvironment.Prod
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,6 @@ class OnboardingActivity : ComponentActivity() {

private val shouldDisplayRequiredLogin by lazy { intent.getBooleanExtra(EXTRA_REQUIRED_LOGIN_KEY, false) }

@Inject
lateinit var accountPreferences: AccountPreferences

@Inject
lateinit var accountUtils: AccountUtils

Expand Down Expand Up @@ -206,8 +203,8 @@ class OnboardingActivity : ComponentActivity() {
areButtonsLoading = false
}

private fun Activity.completeOnboarding() {
accountPreferences.isOnboardingDone = true
private suspend fun Activity.completeOnboarding() {
AccountPreferences().isOnboardingDone = true

Intent(this, MainActivity::class.java).also(::startActivity)
finish()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ fun TransferItem(
Column(modifier = Modifier.weight(1.0f)) {

Text(
text = createdDate,
text = transfer.title ?: createdDate,
style = SwissTransferTheme.typography.bodyMedium,
color = SwissTransferTheme.colors.primaryTextColor,
maxLines = 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,46 +37,58 @@ private val now get() = Clock.System.now().epochSeconds
val transfersPreviewData = listOf(
TransferUi(
uuid = UUID.randomUUID().toString(),
linkId = UUID.randomUUID().toString(),
createdDateTimestamp = now - (0.5f * SECONDS_IN_A_DAY).toLong(),
expirationDateTimestamp = now + 3 * SECONDS_IN_A_DAY,
sizeUploaded = 237_866_728L,
downloadLimit = 250,
downloadLeft = 123,
title = "Transfer title",
message = "3ème transfert. RAS.",
password = "my password",
files = filesPreviewData,
apiSource = TransferUi.ApiSource.V1,
),
TransferUi(
uuid = UUID.randomUUID().toString(),
linkId = UUID.randomUUID().toString(),
createdDateTimestamp = now - (0.6f * SECONDS_IN_A_DAY).toLong(),
expirationDateTimestamp = now + 3 * SECONDS_IN_A_DAY,
sizeUploaded = 237_866_728L,
downloadLimit = 250,
downloadLeft = 123,
title = null,
message = null,
password = "my password",
files = filesPreviewData,
apiSource = TransferUi.ApiSource.V1,
),
TransferUi(
uuid = UUID.randomUUID().toString(),
linkId = UUID.randomUUID().toString(),
createdDateTimestamp = now - 5L * SECONDS_IN_A_DAY,
expirationDateTimestamp = now + 5L * SECONDS_IN_A_DAY,
sizeUploaded = 89_723_143L,
downloadLimit = 20,
downloadLeft = 0,
title = null,
message = null,
password = null,
files = filesPreviewData,
apiSource = TransferUi.ApiSource.V2,
),
TransferUi(
uuid = UUID.randomUUID().toString(),
linkId = UUID.randomUUID().toString(),
createdDateTimestamp = now - 30L * SECONDS_IN_A_DAY,
expirationDateTimestamp = now - 4L * SECONDS_IN_A_DAY,
sizeUploaded = 57_689_032L,
downloadLimit = 1,
downloadLeft = 1,
title = null,
message = "Coucou c'est moi le message de description du transfert.",
password = "password",
files = filesPreviewData,
apiSource = TransferUi.ApiSource.V2,
),
)
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ private fun Theme?.getString(): String {

@Composable
private fun ValidityPeriod?.getString(): String {
return this?.value?.toInt()?.let {
return this?.days?.let {
pluralStringResource(R.plurals.settingsValidityPeriodValue, it, it)
} ?: ""
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ enum class ValidityPeriodOption(

@Composable
private fun getValidityPeriodTitle(validityPeriod: ValidityPeriod): String {
val count = validityPeriod.value.toInt()
val count = validityPeriod.days
return pluralStringResource(R.plurals.settingsValidityPeriodValue, count, count)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.PermissionState
import com.google.accompanist.permissions.rememberPermissionState
import com.infomaniak.core.ui.compose.margin.Margin
import com.infomaniak.core.ui.compose.preview.PreviewAllWindows
import com.infomaniak.core.common.utils.FORMAT_DATE_FULL
import com.infomaniak.core.common.utils.format
import com.infomaniak.core.ui.compose.margin.Margin
import com.infomaniak.core.ui.compose.preview.PreviewAllWindows
import com.infomaniak.multiplatform_swisstransfer.common.ext.toDateFromSeconds
import com.infomaniak.multiplatform_swisstransfer.common.interfaces.ui.FileUi
import com.infomaniak.multiplatform_swisstransfer.common.interfaces.ui.TransferUi
Expand Down Expand Up @@ -106,6 +106,7 @@ import com.infomaniak.swisstransfer.ui.screen.main.transferdetails.emptystate.Em
import com.infomaniak.swisstransfer.ui.screen.newtransfer.pickfiles.components.DeeplinkPasswordAlertDialog
import com.infomaniak.swisstransfer.ui.theme.LocalWindowAdaptiveInfo
import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme
import com.infomaniak.swisstransfer.ui.utils.isV1
import com.infomaniak.swisstransfer.ui.utils.isWindowSmall
import com.infomaniak.swisstransfer.ui.utils.openFile
import com.infomaniak.swisstransfer.ui.utils.shareText
Expand Down Expand Up @@ -244,14 +245,18 @@ private fun TransferDetailsScreen(
}
}

val title = getTransfer().title ?: getTransfer().createdDateTimestamp.toDateFromSeconds().format(FORMAT_DATE_FULL)

SwissTransferScaffold(
topBar = {
SwissTransferTopAppBar(
title = getTransfer().createdDateTimestamp.toDateFromSeconds().format(FORMAT_DATE_FULL),
title = title,
navigationIcon = { if (windowAdaptiveInfo.isWindowSmall()) TopAppBarButtons.Back(onClick = navigateBack ?: {}) },
actions = {
when (direction) {
TransferDirection.SENT -> downloadUi.TopAppBarButton()
TransferDirection.SENT -> {
if (getTransfer().isV1()) downloadUi.TopAppBarButton()
}
TransferDirection.RECEIVED -> TopAppBarButtons.QrCode {
MatomoSwissTransfer.trackReceivedTransferEvent(MatomoName.ShowQRCode)
showQrCodeBottomSheet = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ class TransferDetailsViewModel @Inject constructor(

private fun TransferUi?.toUiState(isInLocal: Boolean): TransferDetailsUiState = when (this?.transferStatus) {
TransferStatus.NOT_YET_FETCHED -> Loading
TransferStatus.PENDING_UPLOAD -> Loading
TransferStatus.UNKNOWN -> Unknown
TransferStatus.READY -> Success(this)
TransferStatus.EXPIRED_DOWNLOAD_QUOTA -> ByQuota(downloadLimit, isInLocal)
Expand Down
Loading
Loading