Loading app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonState.kt 0 → 100644 +103 −0 Original line number Diff line number Diff line /* * Copyright (C) 2026 e Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ package foundation.e.apps.ui.compose.state import androidx.annotation.StringRes import foundation.e.apps.data.enums.Status /* * Central UI contract for the primary action button in search results. * UI layers render purely from this state; business logic must not leak into Composables. */ data class InstallButtonState( val label: ButtonLabel = ButtonLabel(), val enabled: Boolean = true, val style: InstallButtonStyle = InstallButtonStyle.AccentOutline, val showProgressBar: Boolean = false, val progressPercentText: String? = null, val actionIntent: InstallButtonAction = InstallButtonAction.NoOp, @StringRes val snackbarMessageId: Int? = null, val dialogType: InstallDialogType? = null, val statusTag: StatusTag = StatusTag.Unknown, val rawStatus: Status = Status.UNAVAILABLE, ) { fun isInProgress(): Boolean { return showProgressBar || actionIntent == InstallButtonAction.CancelDownload || rawStatus in Status.downloadStatuses || rawStatus == Status.INSTALLING } } /* * UI label that can be backed by a string resource or a literal string (e.g., price). */ data class ButtonLabel( @StringRes val resId: Int? = null, val text: String? = null, ) /* * Visual treatment tokens mapped to Compose theme in the UI layer. */ enum class InstallButtonStyle { AccentFill, // Accent background, white text (matches installed/updatable legacy state) AccentOutline, // Transparent background, accent stroke + text Disabled, // Light-grey stroke + text } /* * Intent describing the side-effect the UI host should execute on click. */ enum class InstallButtonAction { Install, CancelDownload, OpenAppOrPwa, UpdateSelfConfirm, ShowPaidDialog, ShowBlockedSnackbar, NoOp, } /* * Dialog variants initiated from the button state when action requires confirmation. */ enum class InstallDialogType { SelfUpdateConfirmation, PaidAppDialog, } /* * Lightweight status marker useful for tests and debugging to assert mapping branch taken. */ enum class StatusTag { Installed, Updatable, UnavailableFree, UnavailablePaid, UnavailableUnsupported, Downloading, Installing, Blocked, InstallationIssue, Unknown, } /* * Purchase resolution states, mirroring legacy branching. */ sealed class PurchaseState { object Unknown : PurchaseState() object Loading : PurchaseState() object Purchased : PurchaseState() object NotPurchased : PurchaseState() } app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapper.kt +0 −82 Original line number Diff line number Diff line Loading @@ -18,94 +18,12 @@ package foundation.e.apps.ui.compose.state import androidx.annotation.StringRes import foundation.e.apps.R import foundation.e.apps.data.application.data.Application import foundation.e.apps.data.enums.Status import foundation.e.apps.data.enums.User import foundation.e.apps.install.pkg.InstallerService /* * Central UI contract for the primary action button in search results. * UI layers render purely from this state; business logic must not leak into Composables. */ data class InstallButtonState( val label: ButtonLabel = ButtonLabel(), val enabled: Boolean = true, val style: InstallButtonStyle = InstallButtonStyle.AccentOutline, val showProgressBar: Boolean = false, val progressPercentText: String? = null, val actionIntent: InstallButtonAction = InstallButtonAction.NoOp, @StringRes val snackbarMessageId: Int? = null, val dialogType: InstallDialogType? = null, val statusTag: StatusTag = StatusTag.Unknown, val rawStatus: Status = Status.UNAVAILABLE, ) { fun isInProgress(): Boolean { return showProgressBar || actionIntent == InstallButtonAction.CancelDownload || rawStatus in Status.downloadStatuses || rawStatus == Status.INSTALLING } } /* * UI label that can be backed by a string resource or a literal string (e.g., price). */ data class ButtonLabel( @StringRes val resId: Int? = null, val text: String? = null, ) /* * Visual treatment tokens mapped to Compose theme in the UI layer. */ enum class InstallButtonStyle { AccentFill, // Accent background, white text (matches installed/updatable legacy state) AccentOutline, // Transparent background, accent stroke + text Disabled, // Light-grey stroke + text } /* * Intent describing the side-effect the UI host should execute on click. */ enum class InstallButtonAction { Install, CancelDownload, OpenAppOrPwa, UpdateSelfConfirm, ShowPaidDialog, ShowBlockedSnackbar, NoOp, } /* * Dialog variants initiated from the button state when action requires confirmation. */ enum class InstallDialogType { SelfUpdateConfirmation, PaidAppDialog, } /* * Lightweight status marker useful for tests and debugging to assert mapping branch taken. */ enum class StatusTag { Installed, Updatable, UnavailableFree, UnavailablePaid, UnavailableUnsupported, Downloading, Installing, Blocked, InstallationIssue, Unknown, } /* * Purchase resolution states, mirroring legacy branching. */ sealed class PurchaseState { object Unknown : PurchaseState() object Loading : PurchaseState() object Purchased : PurchaseState() object NotPurchased : PurchaseState() } /* * Map raw application + contextual signals into a single button state. * Keep pure: no side effects; callers handle actions. Loading Loading
app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonState.kt 0 → 100644 +103 −0 Original line number Diff line number Diff line /* * Copyright (C) 2026 e Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ package foundation.e.apps.ui.compose.state import androidx.annotation.StringRes import foundation.e.apps.data.enums.Status /* * Central UI contract for the primary action button in search results. * UI layers render purely from this state; business logic must not leak into Composables. */ data class InstallButtonState( val label: ButtonLabel = ButtonLabel(), val enabled: Boolean = true, val style: InstallButtonStyle = InstallButtonStyle.AccentOutline, val showProgressBar: Boolean = false, val progressPercentText: String? = null, val actionIntent: InstallButtonAction = InstallButtonAction.NoOp, @StringRes val snackbarMessageId: Int? = null, val dialogType: InstallDialogType? = null, val statusTag: StatusTag = StatusTag.Unknown, val rawStatus: Status = Status.UNAVAILABLE, ) { fun isInProgress(): Boolean { return showProgressBar || actionIntent == InstallButtonAction.CancelDownload || rawStatus in Status.downloadStatuses || rawStatus == Status.INSTALLING } } /* * UI label that can be backed by a string resource or a literal string (e.g., price). */ data class ButtonLabel( @StringRes val resId: Int? = null, val text: String? = null, ) /* * Visual treatment tokens mapped to Compose theme in the UI layer. */ enum class InstallButtonStyle { AccentFill, // Accent background, white text (matches installed/updatable legacy state) AccentOutline, // Transparent background, accent stroke + text Disabled, // Light-grey stroke + text } /* * Intent describing the side-effect the UI host should execute on click. */ enum class InstallButtonAction { Install, CancelDownload, OpenAppOrPwa, UpdateSelfConfirm, ShowPaidDialog, ShowBlockedSnackbar, NoOp, } /* * Dialog variants initiated from the button state when action requires confirmation. */ enum class InstallDialogType { SelfUpdateConfirmation, PaidAppDialog, } /* * Lightweight status marker useful for tests and debugging to assert mapping branch taken. */ enum class StatusTag { Installed, Updatable, UnavailableFree, UnavailablePaid, UnavailableUnsupported, Downloading, Installing, Blocked, InstallationIssue, Unknown, } /* * Purchase resolution states, mirroring legacy branching. */ sealed class PurchaseState { object Unknown : PurchaseState() object Loading : PurchaseState() object Purchased : PurchaseState() object NotPurchased : PurchaseState() }
app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapper.kt +0 −82 Original line number Diff line number Diff line Loading @@ -18,94 +18,12 @@ package foundation.e.apps.ui.compose.state import androidx.annotation.StringRes import foundation.e.apps.R import foundation.e.apps.data.application.data.Application import foundation.e.apps.data.enums.Status import foundation.e.apps.data.enums.User import foundation.e.apps.install.pkg.InstallerService /* * Central UI contract for the primary action button in search results. * UI layers render purely from this state; business logic must not leak into Composables. */ data class InstallButtonState( val label: ButtonLabel = ButtonLabel(), val enabled: Boolean = true, val style: InstallButtonStyle = InstallButtonStyle.AccentOutline, val showProgressBar: Boolean = false, val progressPercentText: String? = null, val actionIntent: InstallButtonAction = InstallButtonAction.NoOp, @StringRes val snackbarMessageId: Int? = null, val dialogType: InstallDialogType? = null, val statusTag: StatusTag = StatusTag.Unknown, val rawStatus: Status = Status.UNAVAILABLE, ) { fun isInProgress(): Boolean { return showProgressBar || actionIntent == InstallButtonAction.CancelDownload || rawStatus in Status.downloadStatuses || rawStatus == Status.INSTALLING } } /* * UI label that can be backed by a string resource or a literal string (e.g., price). */ data class ButtonLabel( @StringRes val resId: Int? = null, val text: String? = null, ) /* * Visual treatment tokens mapped to Compose theme in the UI layer. */ enum class InstallButtonStyle { AccentFill, // Accent background, white text (matches installed/updatable legacy state) AccentOutline, // Transparent background, accent stroke + text Disabled, // Light-grey stroke + text } /* * Intent describing the side-effect the UI host should execute on click. */ enum class InstallButtonAction { Install, CancelDownload, OpenAppOrPwa, UpdateSelfConfirm, ShowPaidDialog, ShowBlockedSnackbar, NoOp, } /* * Dialog variants initiated from the button state when action requires confirmation. */ enum class InstallDialogType { SelfUpdateConfirmation, PaidAppDialog, } /* * Lightweight status marker useful for tests and debugging to assert mapping branch taken. */ enum class StatusTag { Installed, Updatable, UnavailableFree, UnavailablePaid, UnavailableUnsupported, Downloading, Installing, Blocked, InstallationIssue, Unknown, } /* * Purchase resolution states, mirroring legacy branching. */ sealed class PurchaseState { object Unknown : PurchaseState() object Loading : PurchaseState() object Purchased : PurchaseState() object NotPurchased : PurchaseState() } /* * Map raw application + contextual signals into a single button state. * Keep pure: no side effects; callers handle actions. Loading