Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
27 changes: 18 additions & 9 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,29 +1,38 @@
name: Publish

on:
workflow_dispatch:
release:
types: [released]

permissions:
id-token: write
contents: read

jobs:
publish:
name: Upload archives
runs-on: macos-latest
permissions:
id-token: write # OIDC for npm trusted publishers
contents: read
steps:
- name: Check out code
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Setup node
uses: actions/setup-node@v4
with:
node-version: '22.x'
registry-url: 'https://registry.npmjs.org'

- name: Upgrade npm
run: npm install -g npm@11.7.0

- name: Build
run: |
yarn
yarn build

- name: Setup node for publishing
uses: actions/setup-node@v3
with:
node-version: '16.x'
registry-url: 'https://registry.npmjs.org'

- name: Publish to npm
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
2 changes: 1 addition & 1 deletion QonversionCapacitorPlugin.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ Pod::Spec.new do |s|
s.ios.deployment_target = '14.0'
s.dependency 'Capacitor'
s.swift_version = '5.1'
s.dependency "QonversionSandwich", "7.3.1"
s.dependency "QonversionSandwich", "7.4.0"
end
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ dependencies {
implementation project(':capacitor-android')
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
implementation 'androidx.core:core-ktx:1.13.1'
implementation "io.qonversion:sandwich:7.3.1"
implementation "io.qonversion:sandwich:7.4.0"
testImplementation "junit:junit:$junitVersion"
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
Expand Down
10 changes: 9 additions & 1 deletion android/src/main/java/io/qonversion/capacitor/NoCodesPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ class NoCodesPlugin : Plugin() {

val proxyUrl = call.getString("proxyUrl")
val locale = call.getString("locale")
val theme = call.getString("theme")

noCodesSandwich.initialize(context, projectKey, proxyUrl, locale = locale)
noCodesSandwich.initialize(context, projectKey, proxyUrl, locale = locale, theme = theme)
noCodesSandwich.setDelegate(noCodesEventListener)

val source = call.getString("source")
Expand Down Expand Up @@ -97,6 +98,13 @@ class NoCodesPlugin : Plugin() {
call.resolve()
}

@PluginMethod
fun setTheme(call: PluginCall) {
val theme = call.getString("theme")
noCodesSandwich.setTheme(theme)
call.resolve()
}

@PluginMethod
fun setPurchaseDelegate(call: PluginCall) {
noCodesSandwich.setPurchaseDelegate(purchaseDelegateBridge)
Expand Down
2 changes: 1 addition & 1 deletion example/android/capacitor.settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ include ':capacitor-splash-screen'
project(':capacitor-splash-screen').projectDir = new File('../node_modules/@capacitor/splash-screen/android')

include ':qonversion-capacitor-plugin'
project(':qonversion-capacitor-plugin').projectDir = new File('../node_modules/@qonversion/capacitor-plugin/android')
project(':qonversion-capacitor-plugin').projectDir = new File('../../android')
2 changes: 1 addition & 1 deletion example/android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
8 changes: 4 additions & 4 deletions example/ios/App/App.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
Expand Down Expand Up @@ -334,7 +334,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
Expand All @@ -351,7 +351,7 @@
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 5ZBNSPDUJ2;
INFOPLIST_FILE = App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.0;
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
Expand All @@ -372,7 +372,7 @@
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 5ZBNSPDUJ2;
INFOPLIST_FILE = App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = io.qonversion.sample;
Expand Down
4 changes: 2 additions & 2 deletions example/ios/App/Podfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'

platform :ios, '14.0'
platform :ios, '15.0'
use_frameworks!

# workaround to avoid Xcode caching of Pods that requires
Expand All @@ -13,7 +13,7 @@ def capacitor_pods
pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
pod 'CapacitorCamera', :path => '../../node_modules/@capacitor/camera'
pod 'CapacitorSplashScreen', :path => '../../node_modules/@capacitor/splash-screen'
pod 'QonversionCapacitorPlugin', :path => '../../node_modules/@qonversion/capacitor-plugin'
pod 'QonversionCapacitorPlugin', :path => '../../..'
end

target 'App' do
Expand Down
42 changes: 21 additions & 21 deletions example/ios/App/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
PODS:
- Capacitor (7.3.0):
- Capacitor (8.0.1):
- CapacitorCordova
- CapacitorCamera (7.0.1):
- CapacitorCamera (8.0.0):
- Capacitor
- CapacitorCordova (7.3.0)
- CapacitorSplashScreen (7.0.1):
- CapacitorCordova (8.0.1)
- CapacitorSplashScreen (8.0.0):
- Capacitor
- Qonversion (6.3.1):
- Qonversion/Main (= 6.3.1)
- Qonversion/Main (6.3.1)
- QonversionCapacitorPlugin (0.3.1):
- Qonversion (6.4.0):
- Qonversion/Main (= 6.4.0)
- Qonversion/Main (6.4.0)
- QonversionCapacitorPlugin (1.0.0):
- Capacitor
- QonversionSandwich (= 7.3.1)
- QonversionSandwich (7.3.1):
- Qonversion (= 6.3.1)
- QonversionSandwich (= 7.4.0)
- QonversionSandwich (7.4.0):
- Qonversion (= 6.4.0)

DEPENDENCIES:
- "Capacitor (from `../../node_modules/@capacitor/ios`)"
- "CapacitorCamera (from `../../node_modules/@capacitor/camera`)"
- "CapacitorCordova (from `../../node_modules/@capacitor/ios`)"
- "CapacitorSplashScreen (from `../../node_modules/@capacitor/splash-screen`)"
- "QonversionCapacitorPlugin (from `../../node_modules/@qonversion/capacitor-plugin`)"
- QonversionCapacitorPlugin (from `../../..`)

SPEC REPOS:
trunk:
Expand All @@ -37,17 +37,17 @@ EXTERNAL SOURCES:
CapacitorSplashScreen:
:path: "../../node_modules/@capacitor/splash-screen"
QonversionCapacitorPlugin:
:path: "../../node_modules/@qonversion/capacitor-plugin"
:path: "../../.."

SPEC CHECKSUMS:
Capacitor: fbd134fa28e503720559ecddb5ab6b41d69de347
CapacitorCamera: eb8687d8687fed853598ec9460d94bcd5e16babe
CapacitorCordova: 2685f5c43675793b5f06dfd66b3b26268f003b97
CapacitorSplashScreen: 19cd3573e57507e02d6f34597a8c421e00931487
Qonversion: 48d745b4ada2b50c57bf58d82c14822675ef3535
QonversionCapacitorPlugin: 79081868e54201f0319bdd66575f6ae136a2f44e
QonversionSandwich: d3e6fd4882ac0778b8e9708248117d36a51000c0
Capacitor: 2d8b1a05870ddb600b0e1e32b83fcf0890c244e1
CapacitorCamera: 05ac5bd4499ed4b8cf5358d1b4a874b385de7b4d
CapacitorCordova: 0d65b9bb74e995dcecb9463f34f1af2aba6f955c
CapacitorSplashScreen: 4b78177a21f0f73ccc1c78dd93b2a94854ac4b83
Qonversion: f7620e1cc3b03541b9cf4a0ed357a5646d123fe3
QonversionCapacitorPlugin: 1d8ef7c70cdc188e8aa62f7db46080b722c48096
QonversionSandwich: 58a58f43664d2ddb755b315b51adfe9392ede3f9

PODFILE CHECKSUM: afe3f9454c98dc22ff3619593d5dcbd43e1499e8
PODFILE CHECKSUM: 997ea9e24aadc2907f2351506e72f75dadd36129

COCOAPODS: 1.16.2
69 changes: 69 additions & 0 deletions example/src/app/screens/NoCodesScreen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
NoCodesConfigBuilder,
ScreenPresentationConfig,
ScreenPresentationStyle,
NoCodesTheme,
Qonversion,
type NoCodesAction,
type NoCodesError,
Expand Down Expand Up @@ -102,6 +103,26 @@ export function renderNoCodesScreen(): string {
</div>
</div>

<div class="section">
<div class="card">
<h3 class="card-title">Theme</h3>
<p style="color: var(--color-text-muted); font-size: 13px; margin-bottom: 12px;">
Set the theme mode for No-Code screens. Controls how screens adapt to light/dark themes.
</p>
<div class="button-row">
<button class="btn btn-outline" id="set-theme-auto" ${!noCodesInitialized ? 'disabled' : ''}>
Auto
</button>
<button class="btn btn-outline" id="set-theme-light" ${!noCodesInitialized ? 'disabled' : ''}>
Light
</button>
<button class="btn btn-outline" id="set-theme-dark" ${!noCodesInitialized ? 'disabled' : ''}>
Dark
</button>
</div>
</div>
</div>

<div class="section">
<button class="btn btn-outline btn-block" id="close-nocodes" ${!noCodesInitialized ? 'disabled' : ''}>
Close No-Codes Screen
Expand Down Expand Up @@ -162,6 +183,15 @@ function updateNoCodesStatus(): void {

const resetBtn = document.getElementById('reset-locale') as HTMLButtonElement;
if (resetBtn) resetBtn.disabled = !noCodesInitialized;

const themeAutoBtn = document.getElementById('set-theme-auto') as HTMLButtonElement;
if (themeAutoBtn) themeAutoBtn.disabled = !noCodesInitialized;

const themeLightBtn = document.getElementById('set-theme-light') as HTMLButtonElement;
if (themeLightBtn) themeLightBtn.disabled = !noCodesInitialized;

const themeDarkBtn = document.getElementById('set-theme-dark') as HTMLButtonElement;
if (themeDarkBtn) themeDarkBtn.disabled = !noCodesInitialized;

const closeBtn = document.getElementById('close-nocodes') as HTMLButtonElement;
if (closeBtn) closeBtn.disabled = !noCodesInitialized;
Expand Down Expand Up @@ -361,6 +391,45 @@ export function setupNoCodesScreenEvents(): void {
}
});

// Set theme - Auto
document.getElementById('set-theme-auto')?.addEventListener('click', () => {
try {
console.log('🔄 [NoCodes] Setting theme: Auto');
NoCodes.getSharedInstance().setTheme(NoCodesTheme.AUTO);

store.dispatch({ type: 'ADD_NOCODES_EVENT', payload: 'Theme set: Auto' });
showToast('Theme set to Auto', 'success');
} catch (error: any) {
showToast(error.message || 'Failed to set theme', 'error');
}
});

// Set theme - Light
document.getElementById('set-theme-light')?.addEventListener('click', () => {
try {
console.log('🔄 [NoCodes] Setting theme: Light');
NoCodes.getSharedInstance().setTheme(NoCodesTheme.LIGHT);

store.dispatch({ type: 'ADD_NOCODES_EVENT', payload: 'Theme set: Light' });
showToast('Theme set to Light', 'success');
} catch (error: any) {
showToast(error.message || 'Failed to set theme', 'error');
}
});

// Set theme - Dark
document.getElementById('set-theme-dark')?.addEventListener('click', () => {
try {
console.log('🔄 [NoCodes] Setting theme: Dark');
NoCodes.getSharedInstance().setTheme(NoCodesTheme.DARK);

store.dispatch({ type: 'ADD_NOCODES_EVENT', payload: 'Theme set: Dark' });
showToast('Theme set to Dark', 'success');
} catch (error: any) {
showToast(error.message || 'Failed to set theme', 'error');
}
});

// Close
document.getElementById('close-nocodes')?.addEventListener('click', () => {
try {
Expand Down
10 changes: 9 additions & 1 deletion ios/Sources/QonversionPlugin/NoCodesPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class NoCodesPlugin: CAPPlugin, CAPBridgedPlugin {
CAPPluginMethod(name: "close", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "setPurchaseDelegate", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "setLocale", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "setTheme", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "delegatedPurchaseCompleted", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "delegatedPurchaseFailed", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "delegatedRestoreCompleted", returnType: CAPPluginReturnPromise),
Expand All @@ -37,8 +38,9 @@ public class NoCodesPlugin: CAPPlugin, CAPBridgedPlugin {

let proxyUrl = call.getString("proxyUrl")
let locale = call.getString("locale")
let theme = call.getString("theme")

noCodesSandwich?.initialize(projectKey: projectKey, proxyUrl: proxyUrl, locale: locale)
noCodesSandwich?.initialize(projectKey: projectKey, proxyUrl: proxyUrl, locale: locale, theme: theme)

if let source = call.getString("source"),
let version = call.getString("version") {
Expand Down Expand Up @@ -84,6 +86,12 @@ public class NoCodesPlugin: CAPPlugin, CAPBridgedPlugin {
call.resolve()
}

@objc func setTheme(_ call: CAPPluginCall) {
let theme = call.getString("theme")
noCodesSandwich?.setTheme(theme)
call.resolve()
}

@objc func setPurchaseDelegate(_ call: CAPPluginCall) {
purchaseDelegateBridge = NoCodesPurchaseDelegateBridgeImpl { [weak self] productData in
self?.notifyListeners(NoCodesPurchaseEventName, data: productData)
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@qonversion/capacitor-plugin",
"version": "1.0.0",
"version": "1.1.0",
"description": "Qonversion provides full in-app purchases infrastructure, so you do not need to build your own server for receipt validation. Implement in-app subscriptions, validate user receipts, check subscription status, and provide access to your app features and content using our StoreKit wrapper and Google Play Billing wrapper.",
"main": "dist/plugin.cjs.js",
"module": "dist/esm/index.js",
Expand Down
13 changes: 13 additions & 0 deletions src/NoCodesApi.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { PurchaseDelegate } from './dto/PurchaseDelegate';
import { ScreenPresentationConfig } from './dto/ScreenPresentationConfig';
import { NoCodesTheme } from './dto/enums';

export interface NoCodesApi {
/**
Expand Down Expand Up @@ -37,4 +38,16 @@ export interface NoCodesApi {
* @param locale the locale to use (e.g. "en", "de", "fr"), or null to reset to device default.
*/
setLocale(locale: string | null): void;

/**
* Set the theme mode for No-Code screens.
* Controls how screens adapt to light/dark themes.
*
* You may set the theme both after No-Codes SDK initialization with this method
* and during initialization via NoCodesConfigBuilder.setTheme().
*
* @param theme the desired theme mode. Use AUTO to follow device settings,
* LIGHT to force light theme, or DARK to force dark theme.
*/
setTheme(theme: NoCodesTheme): void;
}
Loading