Skip to content

feat: shortcuts info panel #1392

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: feat/shortcuts-customization
Choose a base branch
from

Conversation

Syn-McJ
Copy link
Member

@Syn-McJ Syn-McJ commented May 13, 2025

We want to show an info panel informing users about the shortcut customization feature.

Issue being fixed or feature implemented

  • Info panel UI
  • Show/hide logic

Related PR's and Dependencies

This should be merged before #1385

Screenshots / Videos

How Has This Been Tested?

  • QA (Mobile Team)

Checklist:

  • I have performed a self-review of my own code and added comments where necessary
  • I have added or updated relevant unit/integration/functional/e2e tests

Summary by CodeRabbit

  • New Features

    • Introduced an informational panel to guide users on customizing the shortcut bar, including a new icon and descriptive text.
    • Added a new UI component for displaying information panels with customizable content and actions.
  • Improvements

    • Enhanced theming and typography with additional font styles and colors for a more polished appearance.
    • Updated the background color of menu items to match the app’s theme.
    • Improved shortcut customization guidance by conditionally displaying the info panel based on user actions and preferences.
  • Bug Fixes

    • Improved handling of shortcut data resets to ensure a consistent user experience.
  • Chores

    • Updated dependencies for layout and Compose lifecycle support.

@Syn-McJ Syn-McJ requested a review from HashEngineering May 13, 2025 07:08
@Syn-McJ Syn-McJ self-assigned this May 13, 2025
Copy link
Contributor

coderabbitai bot commented May 13, 2025

Walkthrough

This update introduces a Compose-based informational panel to guide users in customizing shortcut bars, managed by new state logic in the ShortcutsViewModel. The UI theme receives expanded font and color options, and a new vector drawable and string resources are added for shortcut customization. Several code refactors improve preference handling, state management, and flow handling. Compose dependencies are updated, and layout files are adjusted to accommodate the new info panel.

Changes

File(s) Change Summary
build.gradle, wallet/build.gradle Updated constrainLayoutVersion to 2.2.1 and added lifecycle-runtime-compose dependency.
common/src/main/java/org/dash/wallet/common/data/WalletUIConfig.kt Added IS_SHORTCUT_INFO_HIDDEN preference key; refactored shared preference editing to use extension function.
common/src/main/java/org/dash/wallet/common/ui/components/InfoPanel.kt Introduced new composable InfoPanel for displaying information panels, with preview.
common/src/main/java/org/dash/wallet/common/ui/components/MenuItem.kt Changed background color from white to theme-based color.
common/src/main/java/org/dash/wallet/common/ui/components/MyTheme.kt Refactored font family usage, added new text styles (Caption, CaptionMedium), and new color (gray).
wallet/res/drawable/ic_shortcuts.xml Added new vector drawable icon for shortcuts.
wallet/res/layout/home_content.xml Reduced top padding and added a ComposeView for the info panel.
wallet/res/values/strings.xml Added string resources for shortcut customization title and description.
wallet/src/de/schildbach/wallet/ui/main/HeaderBalanceFragment.kt Changed logic for hint visibility to explicitly check for false.
wallet/src/de/schildbach/wallet/ui/main/MainViewModel.kt Converted hideBalance to StateFlow, showTapToHideHint to Flow; simplified null and exception handling.
wallet/src/de/schildbach/wallet/ui/main/WalletFragment.kt Integrated Compose info panel for shortcut customization, adjusted view model scoping, and managed info panel visibility.
wallet/src/de/schildbach/wallet/ui/main/shortcuts/ShortcutProvider.kt Removed filterNotNull(); now explicitly handles null shortcut sets and resets state accordingly.
wallet/src/de/schildbach/wallet/ui/main/shortcuts/ShortcutsViewModel.kt Added state and logic for showing/hiding shortcut info panel, including persistence and upgrade/install detection.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant WalletFragment
    participant ShortcutsViewModel
    participant UI

    User->>WalletFragment: Opens wallet screen
    WalletFragment->>ShortcutsViewModel: Observe showShortcutInfo
    ShortcutsViewModel->>ShortcutsViewModel: Determine if info panel should show (upgrade/install/flag)
    ShortcutsViewModel-->>WalletFragment: showShortcutInfo = true/false
    WalletFragment->>UI: Display InfoPanel if showShortcutInfo = true

    User->>UI: Clicks close on InfoPanel
    UI->>WalletFragment: onAction callback
    WalletFragment->>ShortcutsViewModel: hideShortcutInfo()
    ShortcutsViewModel->>ShortcutsViewModel: Set showShortcutInfo = false, persist flag
    ShortcutsViewModel-->>WalletFragment: showShortcutInfo = false
    WalletFragment->>UI: Hide InfoPanel
Loading

Poem

In the garden of code, a panel appears,
To guide your shortcuts, allaying your fears.
With fonts anew and colors so bright,
A bunny hops in, making things right.
Compose and persist, with a click you shall see—
Custom bars await, as easy as can be!
🐇✨

Tip

⚡️ Faster reviews with caching
  • CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.

Enjoy the performance boost—your workflow just got faster.

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@Syn-McJ Syn-McJ mentioned this pull request May 13, 2025
3 tasks
@Syn-McJ Syn-McJ added this to the 11.3 milestone May 13, 2025
@Syn-McJ
Copy link
Member Author

Syn-McJ commented May 13, 2025

@CodeRabbit review

Copy link
Contributor

coderabbitai bot commented May 13, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
wallet/src/de/schildbach/wallet/ui/main/shortcuts/ShortcutProvider.kt (1)

50-56: Enhanced null handling for shortcut data.

The code now explicitly handles null shortcut sets by resetting to an empty list and returning early, providing clearer control flow compared to the previous implicit filtering approach.

Consider adding a log statement when this occurs to help with debugging if users experience unexpected shortcut resets:

if (shortcuts == null) {
    // DataStore was cleared out, probably due to a reset
+   Log.d("ShortcutProvider", "Shortcut data was null, resetting to empty list")
    _customShortcuts.value = emptyList()
    return@onEach
}
common/src/main/java/org/dash/wallet/common/ui/components/InfoPanel.kt (1)

43-111: Well-structured InfoPanel composable with good UI practices

The InfoPanel composable is well-implemented with clean organization and flexible parameters. It effectively combines layout, theming, and interactive elements.

Consider making the "Close" content description in the action icon (line 104) configurable through a parameter rather than hardcoded, to support different action types and improve accessibility.

@Composable
fun InfoPanel(
    title: String,
    description: String,
    modifier: Modifier = Modifier,
    @DrawableRes leftIconRes: Int? = null,
    @DrawableRes actionIconRes: Int? = null,
+   actionContentDescription: String? = "Close",
    onAction: (() -> Unit)? = null
) {
    // ...
    Icon(
        painter = painterResource(id = actionIconRes),
-       contentDescription = "Close",
+       contentDescription = actionContentDescription,
        tint = MyTheme.Colors.gray
    )
    // ...
}
wallet/src/de/schildbach/wallet/ui/main/shortcuts/ShortcutsViewModel.kt (2)

83-83: Consider limiting logging to debug builds

While logging the shortcuts size is helpful for debugging, consider wrapping it in a condition to only log in debug builds to avoid unnecessary logging in production.

-            .onEach { Log.i("SHORTCUTS", "size: ${it.size}") }
+            .onEach { 
+                if (BuildConfig.DEBUG) {
+                    Log.i("SHORTCUTS", "size: ${it.size}")
+                }
+            }

88-103: Complex visibility logic could benefit from more comments

The logic for determining the initial visibility of the shortcut info panel handles different scenarios well, but could benefit from more detailed inline comments explaining each conditional branch.

        // Check if need to show the shortcut info panel
        viewModelScope.launch {
            val isHidden = walletUIConfig.get(WalletUIConfig.IS_SHORTCUT_INFO_HIDDEN)
+            // Determine whether to show the shortcut info panel based on app state
+            // and user preferences
            showShortcutInfo = if (config.wasUpgraded()) {
                // If upgraded, show immediately if not already hidden
                isHidden != true
            } else if (isHidden == null) {
                // New install and the first time opening the app - don't show
                // Update IS_SHORTCUT_INFO_HIDDEN to detect non-first launch next time
                walletUIConfig.set(WalletUIConfig.IS_SHORTCUT_INFO_HIDDEN, false)
                false
            } else {
                // New install, not the first time opening the app, show if not hidden
                !isHidden
            }
        }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 969e672 and f1b9019.

📒 Files selected for processing (14)
  • build.gradle (1 hunks)
  • common/src/main/java/org/dash/wallet/common/data/WalletUIConfig.kt (3 hunks)
  • common/src/main/java/org/dash/wallet/common/ui/components/InfoPanel.kt (1 hunks)
  • common/src/main/java/org/dash/wallet/common/ui/components/MenuItem.kt (1 hunks)
  • common/src/main/java/org/dash/wallet/common/ui/components/MyTheme.kt (2 hunks)
  • wallet/build.gradle (1 hunks)
  • wallet/res/drawable/ic_shortcuts.xml (1 hunks)
  • wallet/res/layout/home_content.xml (2 hunks)
  • wallet/res/values/strings.xml (1 hunks)
  • wallet/src/de/schildbach/wallet/ui/main/HeaderBalanceFragment.kt (2 hunks)
  • wallet/src/de/schildbach/wallet/ui/main/MainViewModel.kt (6 hunks)
  • wallet/src/de/schildbach/wallet/ui/main/WalletFragment.kt (6 hunks)
  • wallet/src/de/schildbach/wallet/ui/main/shortcuts/ShortcutProvider.kt (2 hunks)
  • wallet/src/de/schildbach/wallet/ui/main/shortcuts/ShortcutsViewModel.kt (3 hunks)
🧰 Additional context used
🧠 Learnings (1)
wallet/src/de/schildbach/wallet/ui/main/shortcuts/ShortcutProvider.kt (1)
Learnt from: Syn-McJ
PR: dashpay/dash-wallet#1389
File: features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/explore/SearchFragment.kt:45-46
Timestamp: 2025-05-07T14:18:11.161Z
Learning: In the ExploreViewModel of the dash-wallet application, `appliedFilters` is a StateFlow (not LiveData), so Flow operators like `distinctUntilChangedBy` can be used with it.
🧬 Code Graph Analysis (1)
wallet/src/de/schildbach/wallet/ui/main/WalletFragment.kt (1)
common/src/main/java/org/dash/wallet/common/ui/components/InfoPanel.kt (1)
  • InfoPanel (43-111)
🔇 Additional comments (41)
build.gradle (1)

31-31: Dependency version update looks good.

Updated ConstraintLayout version from 2.1.4 to 2.2.1 which aligns with the UI updates in this PR.

wallet/res/drawable/ic_shortcuts.xml (1)

1-22: Well-structured vector drawable for shortcuts icon.

The icon is properly defined with appropriate size, viewport, and properly structured paths. The use of fillType="evenOdd" for the first path is appropriate for the compound shape.

common/src/main/java/org/dash/wallet/common/ui/components/MenuItem.kt (1)

59-59: Good theme integration for background color.

Replacing the hardcoded Color.White with MyTheme.Colors.backgroundSecondary improves theme consistency and supports dynamic theming (like dark mode).

wallet/src/de/schildbach/wallet/ui/main/HeaderBalanceFragment.kt (2)

34-34: Added import for observe utility.

The import addition is necessary for the refined state observation logic.


70-70: Improved null handling for boolean state.

Changed from using Elvis operator with a default (showHint ?: true) to an explicit check (showHint != false). This makes the intent clearer - the hint is visible unless explicitly set to false.

wallet/build.gradle (1)

103-103: Added necessary dependency for Compose lifecycle integration.

This dependency is essential for the new Compose-based info panel, enabling lifecycle-aware state collection from the associated ViewModel.

wallet/res/layout/home_content.xml (2)

59-59: Reduced top padding for better vertical spacing.

This adjustment from 54dp to 40dp provides better vertical spacing within the sync_status_pane_parent container, accounting for the new info panel element.


78-82: Added ComposeView for the shortcuts information panel.

The new ComposeView will host the Compose-based InfoPanel component, positioned below the sync and mixing status panels with consistent margin treatment.

wallet/src/de/schildbach/wallet/ui/main/shortcuts/ShortcutProvider.kt (1)

38-39: Improved documentation for minimum shortcuts requirement.

The comment clarifies the logic behind the MINIMUM_SHORTCUTS constant, providing better context for the shortcut management code.

wallet/res/values/strings.xml (1)

426-427: Added strings for shortcut customization guidance.

These strings provide clear instructions to users on how to customize the shortcut bar, enhancing the user experience with intuitive guidance.

common/src/main/java/org/dash/wallet/common/data/WalletUIConfig.kt (3)

30-30: Good addition of the Kotlin extension function for SharedPreferences

Using androidx.core.content.edit import enables a more concise and elegant SharedPreferences edit pattern which is utilized later in the file.


70-70: LGTM: Clear and consistent preference key name

The new preference key IS_SHORTCUT_INFO_HIDDEN follows the existing naming convention and clearly describes its purpose.


117-117: Good refactor to use the Kotlin DSL for SharedPreferences

You've improved code readability by replacing the traditional edit().putString(...).apply() pattern with the more concise Kotlin extension function edit { putString(...) }.

common/src/main/java/org/dash/wallet/common/ui/components/MyTheme.kt (3)

31-34: Good enhancement to font management

Breaking down the generic font family into specific font weight variants improves typography control throughout the app.


59-71: Good addition of Caption text styles

The new Caption and CaptionMedium text styles provide appropriate typography options for the info panel component.


97-97: LGTM: New color for enhanced UI

The new gray color enhances the color palette and will be used for the close icon in the info panel.

common/src/main/java/org/dash/wallet/common/ui/components/InfoPanel.kt (1)

113-123: Good use of Preview composable

Including a preview composable helps with development and QA, providing a sample visualization without running the full app.

wallet/src/de/schildbach/wallet/ui/main/shortcuts/ShortcutsViewModel.kt (2)

76-76: LGTM: Clear state variable for info panel visibility

The new mutable state variable showShortcutInfo clearly represents whether the shortcut info panel should be displayed.


143-148: Clear and concise method to hide info panel

The hideShortcutInfo() method effectively updates both the UI state and persists the preference.

wallet/src/de/schildbach/wallet/ui/main/WalletFragment.kt (13)

25-31: Added necessary Compose UI imports for the new InfoPanel component.

The new imports support the implementation of the Compose-based InfoPanel component that will display shortcut customization guidance.


100-100: Good change: Scoping ShortcutsViewModel to the activity level.

Changing from by viewModels() to by activityViewModels() ensures the shortcut view model state is preserved across navigation events and shared between fragments within the same activity.


162-181: Well-implemented Compose integration for the shortcuts info panel.

The InfoPanel implementation follows best practices by:

  1. Setting a proper composition strategy with ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed
  2. Using conditional rendering based on the view model state
  3. Proper resource string references instead of hardcoded text
  4. Well-structured layout with appropriate modifiers
  5. Including a close action that updates the view model state

466-466: Fixed explicit NavOptions.Builder() qualification.

This change ensures proper resolution of the NavOptions.Builder class, avoiding potential ambiguity with other Builder classes.


511-511: Good UX: Hiding info panel after shortcut customization interaction.

Calling shortcutViewModel.hideShortcutInfo() after a long-press on a shortcut shows good attention to user experience - once the user demonstrates awareness of the customization feature, there's no need to keep showing the guidance panel.


25-31: Appropriate Compose imports added for the new InfoPanel integration.

The necessary imports for Compose UI components have been properly added to support the new InfoPanel implementation.


37-37: Good switch to activityViewModels() for improved lifecycle management.

Changing to activityViewModels() is appropriate for the ShortcutsViewModel since it ensures the shortcut configuration state persists across fragment recreations and is shared within the activity scope.


55-59: Correctly imported shortcut-related classes.

The necessary imports for the shortcut customization feature have been added properly.


81-81: InfoPanel component successfully imported.

The Compose-based InfoPanel component is correctly imported from the common UI components package.


100-100: Appropriate scope change for shortcutViewModel.

Changing the ShortcutsViewModel to be scoped to the activity is beneficial for maintaining state across fragment lifecycle changes, ensuring the shortcut configuration persists appropriately.


162-181: Well-implemented InfoPanel integration with proper lifecycle handling.

The InfoPanel has been properly integrated with:

  1. Correct composition strategy to handle fragment lifecycle
  2. Conditional display based on the viewModel state
  3. Appropriate styling and layout parameters
  4. Correct action handling to hide the panel when closed

The implementation properly follows Compose best practices.


466-466: Fixed NavOptions.Builder() qualification.

Explicitly qualifying NavOptions.Builder() ensures proper resolution of the class, preventing potential ambiguity with other Builder classes.


511-512: Proper handling of shortcut info when user interacts with shortcuts.

Hiding the shortcut info panel when a user performs a long tap on a shortcut is a good UX decision - it assumes the user has discovered the feature and no longer needs guidance.

wallet/src/de/schildbach/wallet/ui/main/MainViewModel.kt (9)

227-231: Improved state handling using StateFlow.

Converting LiveData to StateFlow with proper configuration parameters:

  1. Uses SharingStarted.WhileSubscribed(5000) for efficient resource management
  2. Provides appropriate scoping with viewModelScope
  3. Sets a sensible default value

This modernizes the codebase by leveraging Kotlin Flow's reactive capabilities.


233-233: Simplified property declaration using Flow.

Converting from LiveData to Flow for the tap-to-hide hint improves consistency with other reactive state properties in the class.


429-429: Simplified balance visibility toggle logic.

The previous implementation likely had unnecessary null-checking. This change directly toggles the current state value, making the code more concise and readable.


478-478: Improved exception handling with discard pattern.

Using the underscore in catch (_: Exception) clearly communicates the intention to ignore exceptions without assigning them to an unused variable.


68-71: Proper Flow-related imports added.

The necessary imports for Kotlin Flow APIs have been added to support the state management improvements.


227-231: Improved state management with StateFlow.

Converting hideBalance from LiveData to StateFlow with proper configuration:

  1. Uses stateIn() with appropriate scoping and caching strategy
  2. Sets a sensible timeout (5 seconds) for the WhileSubscribed strategy
  3. Provides a proper initial value

This modernization aligns with Kotlin coroutines best practices.


233-234: Simplified tap-to-hide hint observation.

Converting to a direct Flow observation simplifies the code and removes unnecessary LiveData wrapping.


429-430: Simplified balance visibility toggle logic.

The implementation now directly toggles the current state using the negation operator, making the code more concise and readable.


478-479: Improved exception handling with Kotlin idioms.

Using the Kotlin underscore syntax to ignore the caught exception is cleaner and more idiomatic. This approach clearly communicates that the exception is intentionally ignored while maintaining the necessary catch block.

Copy link
Collaborator

@HashEngineering HashEngineering left a comment

Choose a reason for hiding this comment

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

LGTM

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.

2 participants