Skip to content

feat: Add organization interface - #679

Merged
tevincent merged 17 commits into
mainfrom
organization-interface
Sep 8, 2026
Merged

tevincent merged 17 commits into
mainfrom
organization-interface

Conversation

@aymericmariaux

@aymericmariaux aymericmariaux commented Jul 29, 2026 •

Copy link
Copy Markdown
Contributor

Copilot AI review requested due to automatic review settings July 29, 2026 07:00
@aymericmariaux
aymericmariaux marked this pull request as draft July 29, 2026 07:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds organization selection to sent transfers and new uploads, with organization-aware upload handling.

Changes:

  • Adds organization switcher UI, avatars, localization, and account-scoped transfer views.
  • Propagates organization IDs through upload, finalization, and cleanup.
  • Adds required database and MyKSuite dependencies.

Reviewed changes

Copilot reviewed 39 out of 39 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
gradle/libs.versions.toml Adds STDatabase dependency alias.
app/build.gradle.kts Adds database and MyKSuite dependencies.
app/src/main/res/values/strings.xml Adds organization label.
app/src/main/res/values-sv/strings.xml Adds Swedish label.
app/src/main/res/values-pt/strings.xml Adds Portuguese label.
app/src/main/res/values-pl/strings.xml Adds Polish label.
app/src/main/res/values-nl/strings.xml Adds Dutch label.
app/src/main/res/values-nb/strings.xml Adds Norwegian label.
app/src/main/res/values-it/strings.xml Adds Italian label.
app/src/main/res/values-fr/strings.xml Adds French label.
app/src/main/res/values-fi/strings.xml Adds Finnish label.
app/src/main/res/values-es/strings.xml Adds Spanish label.
app/src/main/res/values-el/strings.xml Adds Greek label.
app/src/main/res/values-de/strings.xml Adds German label.
app/src/main/res/values-da/strings.xml Adds Danish label.
app/src/main/java/com/infomaniak/swisstransfer/upload/UploadSessionStarterInterface.kt Uses the V2 API transfer model.
app/src/main/java/com/infomaniak/swisstransfer/upload/UploadSessionManager.kt Passes organization ID to cleanup.
app/src/main/java/com/infomaniak/swisstransfer/upload/TransferUploaderV2.kt Finalizes organization uploads.
app/src/main/java/com/infomaniak/swisstransfer/upload/NewTransferParamsExt.kt Maps organization ID into requests.
app/src/main/java/com/infomaniak/swisstransfer/upload/NewTransferParams.kt Stores selected organization ID.
app/src/main/java/com/infomaniak/swisstransfer/upload/AbandonedTransferV2CleanupWorker.kt Preserves organization context during cleanup.
app/src/main/java/com/infomaniak/swisstransfer/ui/utils/OrganizationAccountExt.kt Adds organization avatar and tier helpers.
app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/pickfiles/PickFilesViewModel.kt Captures the selected organization.
app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/pickfiles/PickFilesScreen.kt Adds organization selection to transfer options.
app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/pickfiles/components/TransferOptionsTypes.kt Adds the “Send with” option.
app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/transfers/TransfersViewModel.kt Exposes account-level transfer emptiness.
app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/settings/MyAccountViewModel.kt Updates copyright metadata.
app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/settings/MyAccountScreenWrapper.kt Refactors argument formatting.
app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/settings/MyAccountScreen.kt Refactors parameter and call formatting.
app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/sent/SentScreen.kt Adds organization switching to sent transfers.
app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/received/ReceivedScreen.kt Uses account-level empty state.
app/src/main/java/com/infomaniak/swisstransfer/ui/OnboardingActivity.kt Names the login callback argument.
app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/Organization.kt Adds the organization vector icon.
app/src/main/java/com/infomaniak/swisstransfer/ui/components/transfer/TransferItemList.kt Supports optional list headers.
app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferBottomSheet.kt Adjusts content spacing.
app/src/main/java/com/infomaniak/swisstransfer/ui/components/OrganizationSwitcherViewModel.kt Manages organization selection state.
app/src/main/java/com/infomaniak/swisstransfer/ui/components/OrganizationSwitcherBottomSheet.kt Adds the organization picker sheet.
app/src/main/java/com/infomaniak/swisstransfer/ui/components/OrganizationSwitcher.kt Adds the organization switcher control.

Comment thread app/build.gradle.kts
Comment thread gradle/libs.versions.toml

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 40 out of 40 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (4)

gradle/libs.versions.toml:21

  • This artifact still resolves through swisstransfer = "10.1.0", but organization support (including OrganizationAccount, the new AccountManager methods, and the updated upload signatures) only exists in the unmerged dependency PR #312. As submitted, Gradle resolves the older release and the newly added imports/calls cannot compile. Publish the dependent changes and update the shared SwissTransfer version before merging this PR.
    app/src/main/java/com/infomaniak/swisstransfer/ui/components/OrganizationSwitcherBottomSheet.kt:119
  • SharpRippleButton already applies its own selectable using the isSelected argument. Adding another selectable here while leaving that argument at its default false creates conflicting selection semantics, so accessibility services can announce the selected organization as unselected. Pass the state through the component instead of adding a second selectable modifier.
    SharpRippleButton(
        modifier = Modifier
            .height(ORGANIZATION_ITEM_HEIGHT)
            .fillMaxWidth()
            .selectable(selected = isSelected, onClick = onClick),
        onClick = onClick,
    ) {

app/src/main/java/com/infomaniak/swisstransfer/ui/components/OrganizationSwitcherViewModel.kt:45

  • This performs a one-shot organization query only when currentUserFlow emits. The dependent AccountManager.loadUser sets the current user before asynchronously fetching and inserting organizations, so a fresh login commonly queries an empty cache and this flow never observes the later database update; both switchers then remain hidden. Expose/collect an organization-account database flow (or another signal that emits after refresh) instead of mapping only user changes.
    val organizations: StateFlow<List<OrganizationAccount>> = accountManager.currentUserFlow
        .map { user -> user?.let { accountManager.organizationAccountsForUser(it.id) } ?: emptyList() }
        .stateIn(viewModelScope, SharingStarted.Lazily, initialValue = emptyList())

app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/pickfiles/PickFilesViewModel.kt:330

  • The selected organization is copied into the upload request, but file validation still calls pickedFilesIssues() with the global FileUtils.MAX_FILES_SIZE. OrganizationAccount exposes limits.transferTotalSize, so selecting an account with a lower quota leaves Send enabled for an oversized transfer and the request only fails after upload-session creation. Make the validation react to the selected organization's limit and use that value in the max-size issue.
    private suspend fun extractNewTransferParams() = NewTransferParams(
        validityPeriod = selectedValidityPeriodOption.value.apiValue,
        authorEmail = if (selectedTransferTypeFlow.value == TransferTypeUi.Mail) transferAuthorEmail.trim() else "",
        password = if (selectedPasswordOption.value == PasswordTransferOption.ACTIVATED) transferPassword else NO_PASSWORD,
        title = transferTitle,
        message = transferMessage,
        downloadCountLimit = selectedDownloadLimitOption.value.apiValue,
        languageCode = selectedLanguageOption.value.apiValue,
        recipientsEmails = if (selectedTransferTypeFlow.value == TransferTypeUi.Mail) validatedRecipientsEmails else emptySet(),
        type = selectedTransferTypeFlow.value,
        organizationAccountId = accountManager.selectedOrganizationAccount().first()?.id,

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The declared KMP version is incompatible with the new APIs, and organization selection has unresolved asynchronous failure and ordering risks.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Review details

Suppressed comments (2)

gradle/libs.versions.toml:21

  • This alias still resolves to swisstransfer = "10.1.0", which predates the linked KMP PR #312. That release has neither OrganizationAccount nor the new organization-selection and upload method signatures used by this PR, so the app cannot compile against the declared dependencies. Publish/select a KMP version containing #312 and update the shared version before merging.
    app/src/main/java/com/infomaniak/swisstransfer/ui/components/OrganizationSwitcherViewModel.kt:47
  • This suspend database write is unguarded inside a root launch, so a persistence failure escapes the ViewModel coroutine instead of being handled and reported. Match the established pattern in TransfersViewModel.kt:59-65: wrap the call with runCatching { ... }.cancellable() and report failures through SentryLog.
    fun switchToOrganization(organizationAccountId: Long) = viewModelScope.launch(ioDispatcher) {
        accountManager.switchToOrganization(organizationAccountId)
    }
  • Files reviewed: 40/40 changed files
  • Comments generated: 1
  • Review effort level: Balanced

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 40 out of 40 changed files in this pull request and generated no new comments.

Suppressed comments (2)

gradle/libs.versions.toml:21

  • The catalog is still pinned to swisstransfer = "10.1.0", but that release lacks the organization models and the new UploadSessionRequest, AccountManager, and UploadV2Manager APIs referenced by this PR. PR #312 is still unreleased (even 10.1.1 predates it), so the declared dependencies cannot compile this code. Publish/select a KMP release containing #312 and update the catalog version before merging.
    app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/received/ReceivedScreen.kt:64
  • accountTransfersAreEmpty is based on hasAccountTransferFlow(), which intentionally counts only sent transfers for the current account. Using it for isFirstTransfer makes the “Make your first transfer!” prompt appear for users who already have received transfers (or transfers under another account). Expose a separate state derived from !hasAnyTransferFlow() for this FAB, while keeping the account-scoped state for the Sent header.
    val hasNoTransfers by transfersViewModel.accountTransfersAreEmpty.collectAsStateWithLifecycle()

@aymericmariaux
aymericmariaux marked this pull request as ready for review August 12, 2026 14:37
@aymericmariaux
aymericmariaux force-pushed the organization-interface branch from f24b819 to 3a3076b Compare August 12, 2026 14:38
@LouisCAD
LouisCAD self-requested a review August 12, 2026 14:53
@aymericmariaux
aymericmariaux marked this pull request as draft August 13, 2026 06:20

@LouisCAD LouisCAD left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Made a preliminary review. I will do another, more thorough review early next week.

@aymericmariaux
aymericmariaux force-pushed the organization-interface branch from 74d0c9a to c50100f Compare August 14, 2026 08:38
@aymericmariaux
aymericmariaux force-pushed the organization-interface branch from c50100f to 83ee814 Compare August 24, 2026 11:30
@aymericmariaux
aymericmariaux marked this pull request as ready for review August 24, 2026 12:59

@LouisCAD LouisCAD left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice job!

@tevincent
tevincent force-pushed the organization-interface branch from fd874e4 to 2d6feeb Compare September 7, 2026 15:12
@tevincent
tevincent enabled auto-merge September 7, 2026 15:12
# Conflicts:
#	app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/settings/MyAccountScreen.kt
#	app/src/main/res/values-de/strings.xml
@tevincent
tevincent force-pushed the organization-interface branch from aecebd8 to 04a4d96 Compare September 8, 2026 07:01
@sonarqubecloud

sonarqubecloud Bot commented Sep 8, 2026

Copy link
Copy Markdown

@tevincent
tevincent merged commit f1911c0 into main Sep 8, 2026
9 checks passed
@tevincent
tevincent deleted the organization-interface branch September 8, 2026 07:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants