Skip to content

feat: add Purchasely SDK mode setting (full/paywallObserver) with restart#1

Open
kherembourg wants to merge 2 commits intomainfrom
feat/sdk-mode-settings-restart
Open

feat: add Purchasely SDK mode setting (full/paywallObserver) with restart#1
kherembourg wants to merge 2 commits intomainfrom
feat/sdk-mode-settings-restart

Conversation

@kherembourg
Copy link
Contributor

Summary

  • add a cross-platform Purchasely SDK mode setting in Settings (Paywall Observer / Full)
  • persist the selected mode in app storage and default to paywallObserver
  • apply mode at SDK startup on Android and iOS
  • restart SDK when mode changes and show an explicit kill/relaunch alert
  • add solution documentation for this implementation
  • include updated Shaker manual test matrix doc

Key files

  • android/app/src/main/java/com/purchasely/shaker/data/PurchaselySdkMode.kt
  • android/app/src/main/java/com/purchasely/shaker/ShakerApp.kt
  • android/app/src/main/java/com/purchasely/shaker/ui/screen/settings/SettingsViewModel.kt
  • android/app/src/main/java/com/purchasely/shaker/ui/screen/settings/SettingsScreen.kt
  • ios/Shaker/AppViewModel.swift
  • ios/Shaker/Screens/Settings/SettingsViewModel.swift
  • ios/Shaker/Screens/Settings/SettingsScreen.swift
  • docs/solutions/integration-issues/sdk-running-mode-settings-toggle.md

Validation

  • ./gradlew :app:assembleDebug (success)
  • xcodebuild build -workspace Shaker.xcworkspace -scheme Shaker CODE_SIGNING_ALLOWED=NO (success)

@gemini-code-assist
Copy link

Summary of Changes

Hello @kherembourg, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant enhancement to the Shaker application by enabling users to control the Purchasely SDK's running mode directly from the settings. This cross-platform feature ensures that the chosen mode, either 'Paywall Observer' or 'Full', is not only persisted across app sessions but also correctly applied during SDK initialization. The implementation includes a robust mechanism to handle SDK restarts upon mode changes, guiding users through the necessary app relaunch for a seamless experience. This change greatly improves the flexibility and testability of the Purchasely integration.

Highlights

  • Cross-Platform SDK Mode Setting: Introduced a new setting to allow users to switch between 'Paywall Observer' and 'Full' running modes for the Purchasely SDK on both Android and iOS.
  • Persistent Mode Selection: Implemented logic to persist the selected SDK running mode in app storage, ensuring the choice is remembered across app launches and defaults to 'Paywall Observer'.
  • Dynamic SDK Restart: Added functionality to dynamically restart the Purchasely SDK when the running mode is changed, accompanied by an alert prompting the user to kill and relaunch the app for the changes to take full effect.
  • Enhanced Documentation: Provided comprehensive solution documentation for this new feature and updated the manual test matrix to include relevant test cases.
Changelog
  • README.md
    • Updated paywall implementation details to consistently use fetchPresentation + display.
    • Added a new 'Known Constraints' section detailing important usage notes, including the requirement for fetchPresentation + display().
  • android/app/build.gradle.kts
    • Configured the Purchasely API key to prioritize a value from local.properties with a hardcoded default fallback.
  • android/app/src/main/java/com/purchasely/shaker/ShakerApp.kt
    • Imported PurchaselySdkMode and removed PLYRunningMode import.
    • Updated initPurchasely to retrieve the SDK running mode from storage.
    • Added restartPurchaselySdk and getSdkModeFromStorage methods to manage SDK lifecycle and mode persistence.
  • android/app/src/main/java/com/purchasely/shaker/data/PurchaselySdkMode.kt
    • Added a new enum class PurchaselySdkMode to define and manage the different SDK running modes and their storage values.
  • android/app/src/main/java/com/purchasely/shaker/ui/screen/settings/SettingsScreen.kt
    • Imported AlertDialog, TextButton, and PurchaselySdkMode.
    • Implemented a new UI section in the settings screen with a segmented button for selecting the Purchasely SDK running mode.
    • Added an AlertDialog to inform the user about the required app restart after changing the SDK mode.
  • android/app/src/main/java/com/purchasely/shaker/ui/screen/settings/SettingsViewModel.kt
    • Imported ShakerApp and PurchaselySdkMode.
    • Updated the shared preferences name to use PurchaselySdkMode.PREFERENCES_NAME.
    • Introduced _sdkMode and _sdkModeChangeAlert MutableStateFlows to manage the selected SDK mode and restart alert state.
    • Initialized the default SDK mode from storage.
    • Added setSdkMode to update the mode, persist it, and trigger an SDK restart.
    • Added clearSdkModeChangeAlert to dismiss the restart alert.
    • Implemented restartPurchaselySdk to handle the SDK restart logic and display the alert.
  • docs/solutions/integration-issues/sdk-running-mode-settings-toggle.md
    • Added a new solution documentation file detailing the problem, solution, and implementation specifics for toggling the Purchasely SDK running mode on both Android and iOS.
  • docs/testing/manual-test-matrix.md
    • Added a new manual test matrix document for validating Purchasely integration, including various user states, placements, and flows.
  • ios/Shaker/AppViewModel.swift
    • Defined a new PurchaselySDKMode enum to represent SDK running modes, including storage and PLYRunningMode mapping.
    • Extended Notification.Name with purchaselySdkModeDidChange for inter-component communication.
    • Added an observer in init to handle SDK mode change notifications.
    • Modified initPurchasely to use the stored PurchaselySDKMode and dynamically resolve the API key.
    • Implemented restartPurchaselySdk to close current presentations and reinitialize the SDK.
  • ios/Shaker/Screens/Settings/SettingsScreen.swift
    • Added a new 'Purchasely SDK' section with a segmented picker for selecting the SDK mode.
    • Integrated an alert to notify the user about the required app restart after changing the SDK mode.
  • ios/Shaker/Screens/Settings/SettingsViewModel.swift
    • Added @Published properties sdkMode and sdkModeRestartMessage to manage the SDK mode and alert state.
    • Initialized sdkMode from stored preferences.
    • Implemented setSdkMode to update the mode, persist it, post a notification, and set the restart message.
    • Added clearSdkModeRestartMessage to dismiss the alert.
Activity
  • The pull request introduces a new feature to manage Purchasely SDK running modes.
  • Documentation for the new feature has been added.
  • The manual test matrix has been updated to reflect the changes.
  • No specific human review comments or interactions were provided in the context.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

The pull request introduces a new feature allowing users to toggle the Purchasely SDK running mode between 'Paywall Observer' and 'Full' via the app's settings. This change is implemented across both Android and iOS platforms, ensuring persistence of the selected mode and requiring an SDK restart with user notification upon mode change. The README.md and manual-test-matrix.md files have been updated to reflect these changes and provide necessary documentation. The implementation looks solid, with good separation of concerns for the SDK mode logic and UI components.

Comment on lines +10 to +12
| Recipe detail paywall | `fetchPresentation` + `display` | `fetchPresentation` + `display` | `recipe_detail` |
| Favorites paywall | `fetchPresentation` + `display` | `fetchPresentation` + `display` | `favorites` |
| Filters paywall | `fetchPresentation` + `display` | `fetchPresentation` + `display` | `filters` |

Choose a reason for hiding this comment

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

medium

The README.md update correctly reflects the change from presentationView and presentationController to fetchPresentation + display for paywall flows. This is a good clarification for anyone setting up the project.

- You can override it with local config files:
- Android: `android/local.properties` (`purchasely.apiKey=...`)
- iOS: `ios/Config.xcconfig` (`PURCHASELY_API_KEY = ...`)
- Paywall flows require `fetchPresentation + display()`. Do not use convenience APIs like `presentationView` or `presentationController`.

Choose a reason for hiding this comment

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

medium

This new constraint is important for developers integrating the SDK. It clearly states the recommended approach for paywall flows, avoiding potential misuse of convenience APIs.

"PURCHASELY_API_KEY",
"\"6cda6b92-d63c-4444-bd55-5a164c989bd4\""
//"\"${localProperties.getProperty("purchasely.apiKey", "")}\""
"\"${localProperties.getProperty("purchasely.apiKey", "6cda6b92-d63c-4444-bd55-5a164c989bd4")}\""

Choose a reason for hiding this comment

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

medium

The change to use localProperties.getProperty with a default value is a good improvement. It allows for easier local configuration while providing a fallback API key for quick startup, as mentioned in the README.md.

"${localProperties.getProperty("purchasely.apiKey", "6cda6b92-d63c-4444-bd55-5a164c989bd4")}"

import io.purchasely.ext.LogLevel
import io.purchasely.ext.PLYEvent
import io.purchasely.ext.PLYPresentationAction
import io.purchasely.ext.PLYRunningMode

Choose a reason for hiding this comment

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

medium

The import for PLYRunningMode is no longer needed in ShakerApp.kt as PurchaselySdkMode now encapsulates this. Removing unused imports helps keep the code clean.

.start { isConfigured, error ->
if (isConfigured) {
Log.d(TAG, "[Shaker] Purchasely SDK configured successfully")
Log.d(TAG, "[Shaker] Purchasely SDK configured successfully (mode: ${selectedMode.label})")

Choose a reason for hiding this comment

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

medium

Updating the log message to include the selected SDK mode provides more context during debugging and startup, which is very helpful.

Suggested change
Log.d(TAG, "[Shaker] Purchasely SDK configured successfully (mode: ${selectedMode.label})")
Log.d(TAG, "[Shaker] Purchasely SDK configured successfully (mode: ${selectedMode.label})")

Comment on lines +181 to +188
.alert("SDK Restart Required", isPresented: .init(
get: { viewModel.sdkModeRestartMessage != nil },
set: { if !$0 { viewModel.clearSdkModeRestartMessage() } }
)) {
Button("OK") { viewModel.clearSdkModeRestartMessage() }
} message: {
Text(viewModel.sdkModeRestartMessage ?? "")
}

Choose a reason for hiding this comment

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

medium

The alert for SDK restart in iOS is well-implemented, providing clear communication to the user about the required action after changing the SDK mode.

Suggested change
.alert("SDK Restart Required", isPresented: .init(
get: { viewModel.sdkModeRestartMessage != nil },
set: { if !$0 { viewModel.clearSdkModeRestartMessage() } }
)) {
Button("OK") { viewModel.clearSdkModeRestartMessage() }
} message: {
Text(viewModel.sdkModeRestartMessage ?? "")
}
.alert("SDK Restart Required", isPresented: .init(
get: { viewModel.sdkModeRestartMessage != nil },
set: { if !$0 { viewModel.clearSdkModeRestartMessage() } }
)) {
Button("OK") { viewModel.clearSdkModeRestartMessage() }
} message: {
Text(viewModel.sdkModeRestartMessage ?? "")
}

Comment on lines +9 to +10
@Published var sdkMode: PurchaselySDKMode
@Published var sdkModeRestartMessage: String?

Choose a reason for hiding this comment

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

medium

Adding sdkMode and sdkModeRestartMessage as @Published properties ensures that the UI can react to changes in these values, which is essential for the new SDK mode setting feature.

Suggested change
@Published var sdkMode: PurchaselySDKMode
@Published var sdkModeRestartMessage: String?
@Published var sdkMode: PurchaselySDKMode
@Published var sdkModeRestartMessage: String?

Comment on lines +30 to +31
sdkMode = PurchaselySDKMode.current()
sdkModeRestartMessage = nil

Choose a reason for hiding this comment

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

medium

Initializing sdkMode from PurchaselySDKMode.current() and setting sdkModeRestartMessage to nil on initialization ensures the correct state is loaded when the view model is created.

Suggested change
sdkMode = PurchaselySDKMode.current()
sdkModeRestartMessage = nil
sdkMode = PurchaselySDKMode.current()
sdkModeRestartMessage = nil

Comment on lines +96 to +104
func setSdkMode(_ mode: PurchaselySDKMode) {
guard sdkMode != mode else { return }

sdkMode = mode
mode.persist()
NotificationCenter.default.post(name: .purchaselySdkModeDidChange, object: nil)
sdkModeRestartMessage =
"Purchasely SDK switched to \(mode.title). Please kill and relaunch the app."
print("[Shaker] SDK mode updated to \(mode.rawValue)")

Choose a reason for hiding this comment

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

medium

The setSdkMode function correctly updates the sdkMode, persists it, posts a notification for the AppViewModel to handle the SDK restart, and sets the restart message for the UI. This is a well-encapsulated piece of logic.

Suggested change
func setSdkMode(_ mode: PurchaselySDKMode) {
guard sdkMode != mode else { return }
sdkMode = mode
mode.persist()
NotificationCenter.default.post(name: .purchaselySdkModeDidChange, object: nil)
sdkModeRestartMessage =
"Purchasely SDK switched to \(mode.title). Please kill and relaunch the app."
print("[Shaker] SDK mode updated to \(mode.rawValue)")
func setSdkMode(_ mode: PurchaselySDKMode) {
guard sdkMode != mode else { return }
sdkMode = mode
mode.persist()
NotificationCenter.default.post(name: .purchaselySdkModeDidChange, object: nil)
sdkModeRestartMessage =
"Purchasely SDK switched to \(mode.title). Please kill and relaunch the app."
print("[Shaker] SDK mode updated to \(mode.rawValue)")
}

Comment on lines +107 to +109
func clearSdkModeRestartMessage() {
sdkModeRestartMessage = nil
}

Choose a reason for hiding this comment

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

medium

The clearSdkModeRestartMessage function is necessary to dismiss the alert after the user acknowledges it, providing a clean UI state.

Suggested change
func clearSdkModeRestartMessage() {
sdkModeRestartMessage = nil
}
func clearSdkModeRestartMessage() {
sdkModeRestartMessage = nil
}

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.

1 participant

Comments