Skip to content

Commit

Permalink
17 implement skip this version for android (#18)
Browse files Browse the repository at this point in the history
* feat: wip

* refactor: types

* chore: remove default value

* refactor: import

* chore: update example

* chore: wip

* chore: wip

* chore: wip

* ci: enable build ios

* chore: update example

* ci: disable build:ios
  • Loading branch information
duguyihou authored Mar 10, 2024
1 parent a2a22e4 commit 6df5320
Show file tree
Hide file tree
Showing 16 changed files with 200 additions and 132 deletions.
39 changes: 29 additions & 10 deletions android/src/main/java/com/neoversion/NeoPreference.kt
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
package com.neoversion

import android.content.Context
import android.content.SharedPreferences

class NeoPreference(private val context: Context) {
private val sharedPreferences: SharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
class NeoPreference(context: Context) {
private val sharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
fun save(key: String, value: String) {
val editor = sharedPreferences.edit()
editor.putString(key, value)
editor.apply()
}
fun save(key: String, value: Int) {

private fun save(key: String, value: Int) {
val editor = sharedPreferences.edit()
editor.putInt(key, value)
editor.apply()
}
fun save(key : String, status: Boolean){
val editor = sharedPreferences.edit()

fun save(key: String, status: Boolean) {
val editor = sharedPreferences.edit()
editor.putBoolean(key, status)
editor.apply()
}
Expand All @@ -25,27 +26,45 @@ class NeoPreference(private val context: Context) {
return sharedPreferences.getString(key, null)
}

fun getValueInt(key: String): Int {
private fun getValueInt(key: String): Int {
return sharedPreferences.getInt(key, 0)
}

fun getValueBoolean(key: String, defaultValue: Boolean) : Boolean{
fun getValueBoolean(key: String, defaultValue: Boolean): Boolean {
return sharedPreferences.getBoolean(key, defaultValue)
}

fun clearSharedPreferences(){
fun clearSharedPreferences() {
val editor = sharedPreferences.edit()
editor.clear()
editor.apply()
}

fun removeValue(key: String){
fun removeValue(key: String) {
val editor = sharedPreferences.edit()
editor.remove(key)
editor.apply()
}

fun saveStalenessDays(day: Int) {
save(STORED_STALENESS_DAYS, day)
}

fun getStalenessDays(): Int {
return getValueInt(STORED_STALENESS_DAYS)
}

fun saveSkippedVersion(versionCode: Int) {
save(STORED_SKIPPED_VERSION, versionCode)
}

fun getSkippedVersion(): Int {
return getValueInt(STORED_SKIPPED_VERSION)
}

companion object {
const val PREF_NAME = "neo-version-preference"
const val STORED_STALENESS_DAYS = "storedStalenessDays"
const val STORED_SKIPPED_VERSION = "StoredSkippedVersion"
}
}
17 changes: 13 additions & 4 deletions android/src/main/java/com/neoversion/NeoVersionModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ class NeoVersionModule(reactContext: ReactApplicationContext) :

private val appUpdateManager = AppUpdateManagerFactory.create(reactContext)
private val neoPreference = NeoPreference(reactContext)
private var skippedVersionCode = neoPreference.getSkippedVersion()
private var versionCode: Int? = null

@ReactMethod
fun getVersionInfo(promise: Promise) {
Expand All @@ -27,16 +29,18 @@ class NeoVersionModule(reactContext: ReactApplicationContext) :
promise.reject("ERROR", err.toString())
}
appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
val storedStalenessDays = neoPreference.getValueInt("storedStalenessDays")
val storedStalenessDays = neoPreference.getStalenessDays()
versionCode = appUpdateInfo.availableVersionCode()
val updateAvailability = appUpdateInfo.updateAvailability()
val stalenessDays = appUpdateInfo.clientVersionStalenessDays() ?: 0
val isUpdateAvailable = updateAvailability == UpdateAvailability.UPDATE_AVAILABLE && stalenessDays > storedStalenessDays
val isUpdateAvailable =
updateAvailability == UpdateAvailability.UPDATE_AVAILABLE && stalenessDays > storedStalenessDays && versionCode!! > skippedVersionCode
promise.resolve(isUpdateAvailable)
}
}

@ReactMethod
fun startUpdate(updateType: Int = 0, promise: Promise) {
fun startUpdate(updateType: Int, promise: Promise) {
val appUpdateInfoTask = appUpdateManager.appUpdateInfo
appUpdateInfoTask.addOnFailureListener { err: Exception ->
promise.reject("ERROR", err.toString())
Expand All @@ -61,7 +65,12 @@ class NeoVersionModule(reactContext: ReactApplicationContext) :

@ReactMethod
fun presentNextTime(day: Int) {
neoPreference.save("storedStalenessDays", day)
neoPreference.saveStalenessDays(day)
}

@ReactMethod
fun skipThisVersion() {
versionCode?.let { neoPreference.saveSkippedVersion(it) }
}

companion object {
Expand Down
104 changes: 52 additions & 52 deletions example/ios/NeoVersionExample.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1111,7 +1111,7 @@ PODS:
- React-jsi (= 0.73.4)
- React-logger (= 0.73.4)
- React-perflogger (= 0.73.4)
- ReactNativeNeoVersion (0.1.0):
- ReactNativeNeoVersion (0.3.0):
- glog
- RCT-Folly (= 2022.05.16.00)
- React-Core
Expand Down Expand Up @@ -1371,7 +1371,7 @@ SPEC CHECKSUMS:
React-runtimescheduler: ed48e5faac6751e66ee1261c4bd01643b436f112
React-utils: 6e5ad394416482ae21831050928ae27348f83487
ReactCommon: 840a955d37b7f3358554d819446bffcf624b2522
ReactNativeNeoVersion: 88b8dd1c128d799073ebca4d3570c1d29ca9e513
ReactNativeNeoVersion: dae17c1b295fa22b5e2ca930ce76accfe39ff407
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
Yoga: 1b901a6d6eeba4e8a2e8f308f708691cdb5db312

Expand Down
18 changes: 0 additions & 18 deletions src/Android/neoVersion.android.ts

This file was deleted.

40 changes: 40 additions & 0 deletions src/android/alertButton.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { AlertButton } from 'react-native';
import { startUpdate, presentNextTime, skipThisVersion } from './neoVersion';

export const UpdateTypeMap = {
flexible: 0,
immediate: 1,
} as const;

export type UpdateTypeKey = keyof typeof UpdateTypeMap;
export type UpdateTypeVal = (typeof UpdateTypeMap)[UpdateTypeKey];

export const updateButton = (updateType: UpdateTypeKey): AlertButton => {
return {
text: 'Update',
onPress: () => {
startUpdate(updateType);
},
style: 'default',
};
};

export const skipButton = (): AlertButton => {
return {
text: 'Skip this version',
onPress: () => {
skipThisVersion();
},
style: 'default',
};
};

export const nextTimeButton = (day: number): AlertButton => {
return {
text: 'Next Time',
onPress: () => {
presentNextTime(day);
},
style: 'default',
};
};
26 changes: 26 additions & 0 deletions src/android/neoVersion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { NativeModules } from 'react-native';
import { UpdateTypeMap, type UpdateTypeKey } from './alertButton';

const neoVersion = NativeModules.NeoVersion;

export function getVersionInfo(): Promise<boolean> {
return neoVersion.getVersionInfo();
}

// flexible update by default
export async function startUpdate(
updateType: UpdateTypeKey = 'flexible'
): Promise<void> {
const type = UpdateTypeMap[updateType];
return await neoVersion.startUpdate(type);
}

export async function presentNextTime(day: number) {
return await neoVersion.presentNextTime(day);
}

export async function skipThisVersion(): Promise<void> {
return await neoVersion.skipThisVersion();
}

export default neoVersion;
13 changes: 13 additions & 0 deletions src/android/rules.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { AlertButton } from 'react-native';
import { nextTimeButton, skipButton, updateButton } from './alertButton';
import type { AlertType } from '../types';

export const generateAlertButtons = (
alertType: AlertType,
day: number
): AlertButton[] => {
if (alertType === 'force') return [updateButton('immediate')];
if (alertType === 'option')
return [updateButton('flexible'), nextTimeButton(day)];
return [updateButton('flexible'), skipButton(), nextTimeButton(day)];
};
Original file line number Diff line number Diff line change
@@ -1,40 +1,29 @@
import { useEffect } from 'react';
import {
getVersionInfo,
presentNextTime,
startUpdate,
} from './neoVersion.android';
import { getVersionInfo } from './neoVersion';
import { Alert } from 'react-native';
import type { Configuration } from '../types';
import { generateAlertButtons } from './rules';

export const useNeoVersionCheck = (configuration?: Partial<Configuration>) => {
useEffect(() => {
const performVersionCheck = async () => {
const isUpdateAvailable = await getVersionInfo();
const freq = configuration?.frequency ?? 7;
const type = configuration?.alertType ?? 'skip';
if (isUpdateAvailable) {
Alert.alert(
configuration?.title ?? 'Update Available',
configuration?.message ??
'Please update the app to have the best experience',
[
{
text: 'Update',
onPress: () => {
startUpdate();
},
style: 'default',
},
{
text: 'Next time',
onPress: () => {
presentNextTime(configuration?.frequency ?? 7);
},
style: 'default',
},
]
generateAlertButtons(type, freq)
);
}
};
performVersionCheck();
}, [configuration?.frequency, configuration?.message, configuration?.title]);
}, [
configuration?.alertType,
configuration?.frequency,
configuration?.message,
configuration?.title,
]);
};
2 changes: 1 addition & 1 deletion src/index.android.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { useNeoVersionCheck } from './Android/useNeoVersionCheck.android';
export { useNeoVersionCheck } from './android/useNeoVersionCheck';
2 changes: 1 addition & 1 deletion src/index.ios.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { useNeoVersionCheck } from './iOS/useNeoVersionCheck.ios';
export { useNeoVersionCheck } from './ios/useNeoVersionCheck';
6 changes: 1 addition & 5 deletions src/iOS/alertButton.ts → src/ios/alertButton.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import type { AlertButton } from 'react-native';
import {
launchAppStore,
presentNextTime,
skipThisVersion,
} from './neoVersion.ios';
import { launchAppStore, presentNextTime, skipThisVersion } from './neoVersion';

export const updateButton = (): AlertButton => {
return {
Expand Down
2 changes: 1 addition & 1 deletion src/iOS/neoVersion.ios.ts → src/ios/neoVersion.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { NativeModules } from 'react-native';
import type { UpdateType } from '../types';
import type { UpdateType } from './rules';

const neoVersion = NativeModules.NeoVersion;

Expand Down
10 changes: 9 additions & 1 deletion src/iOS/rules.ts → src/ios/rules.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import type { AlertButton } from 'react-native';
import { nextTimeButton, skipButton, updateButton } from './alertButton';
import { type AlertType, type UpdateType, type Rules } from '../types';
import { type AlertType } from '../types';

export type UpdateType = 'major' | 'minor' | 'patch' | 'unknown';
export type Frequency = 0 | 1 | 7;

export type Rules = {
alertType: AlertType;
frequency: Frequency | number;
};

const criticalRules: Rules = {
alertType: 'force',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useEffect } from 'react';
import { Alert } from 'react-native';
import type { Configuration } from '../types';
import { generateAlertButtons, parse, shouldPresentAlert } from './rules';
import { computeDaysSincePresentation, getVersionInfo } from './neoVersion.ios';
import { computeDaysSincePresentation, getVersionInfo } from './neoVersion';

export const useNeoVersionCheck = (configuration?: Partial<Configuration>) => {
useEffect(() => {
Expand Down
14 changes: 0 additions & 14 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,4 @@
export const FrequencyMap = {
immediately: 0,
daily: 1,
weekly: 7,
} as const;

export type FrequencyKey = keyof typeof FrequencyMap;
export type FrequencyVal = (typeof FrequencyMap)[FrequencyKey];
export type AlertType = 'force' | 'option' | 'skip';
export type UpdateType = 'major' | 'minor' | 'patch' | 'unknown';

export type Rules = {
alertType: AlertType;
frequency: FrequencyVal | number;
};

export type Configuration = {
title: string;
Expand Down

0 comments on commit 6df5320

Please sign in to comment.