Skip to content
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

WIP: change android saving #28290

Open
wants to merge 7 commits into
base: nojima/HOTPOT-76-again
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,8 @@ internal class KbModule(reactContext: ReactApplicationContext?) : KbSpec(reactCo
return GuiConfig.getInstance(reactContext.getFilesDir())?.asString()
}


// only old arch, uncomment
// override fun getConstants(): MutableMap<String, Any>? {
// return getTypedExportedConstants()
// }

// newarch @Override
override fun getTypedExportedConstants(): MutableMap<String, Any> {
@ReactMethod(isBlockingSynchronousMethod = true)
override fun getTypedConstants(): WritableMap {
val versionCode: String = getBuildConfigValue("VERSION_CODE").toString()
val versionName: String = getBuildConfigValue("VERSION_NAME").toString()
var isDeviceSecure = false
Expand Down Expand Up @@ -146,18 +140,19 @@ internal class KbModule(reactContext: ReactApplicationContext?) : KbSpec(reactCo
downloadDir = dir.getAbsolutePath()
}
}
val constants: MutableMap<String, Any> = HashMap()
constants.put("androidIsDeviceSecure", isDeviceSecure)
constants.put("androidIsTestDevice", misTestDevice)
constants.put("appVersionCode", versionCode)
constants.put("appVersionName", versionName)
constants.put("darkModeSupported", false)
constants.put("fsCacheDir", cacheDir)
constants.put("fsDownloadDir", downloadDir)
constants.put("guiConfig", readGuiConfig() as Any)
constants.put("serverConfig", serverConfig)
constants.put("uses24HourClock", DateFormat.is24HourFormat(reactContext))
constants.put("version", version())

val constants: WritableMap = Arguments.createMap()
constants.putBoolean("androidIsDeviceSecure", isDeviceSecure)
constants.putBoolean("androidIsTestDevice", misTestDevice)
constants.putString("appVersionCode", versionCode)
constants.putString("appVersionName", versionName)
constants.putBoolean("darkModeSupported", false)
constants.putString("fsCacheDir", cacheDir)
constants.putString("fsDownloadDir", downloadDir)
constants.putString("guiConfig", readGuiConfig())
constants.putString("serverConfig", serverConfig)
constants.putBoolean("uses24HourClock", DateFormat.is24HourFormat(reactContext))
constants.putString("version", version())
return constants
}

Expand Down
4 changes: 2 additions & 2 deletions rnmodules/react-native-kb/android/src/oldarch/KbSpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReadableMap
import java.util.Map
import com.facebook.react.bridge.WritableMap

abstract class KbSpec(context: ReactApplicationContext?) : ReactContextBaseJavaModule(context) {

abstract fun getTypedExportedConstants(): MutableMap<String, Any>
abstract fun getTypedConstants(): WritableMap
abstract fun install(): Boolean
abstract fun getDefaultCountryCode(promise: Promise)
abstract fun logSend(status: String, feedback: String, sendLogs: Boolean, sendMaxBytes: Boolean, traceDir: String, cpuProfileDir: String, promise: Promise)
Expand Down
28 changes: 16 additions & 12 deletions rnmodules/react-native-kb/src/NativeKb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,22 @@ export interface Spec extends TurboModule {
install: () => boolean
addListener: (eventType: string) => void
removeListeners: (count: number) => void
getConstants(): {
androidIsDeviceSecure: boolean
androidIsTestDevice: boolean
appVersionCode: string
appVersionName: string
darkModeSupported: boolean
fsCacheDir: string
fsDownloadDir: string
guiConfig: string
serverConfig: string
uses24HourClock: boolean
version: string
// not used directly, just used to get constants which are individually pulled out, see ./index.tsx
getTypedConstants: () => {
[key: string]: unknown
/*
androidIsDeviceSecure: boolean
androidIsTestDevice: boolean
appVersionCode: string
appVersionName: string
darkModeSupported: boolean
fsCacheDir: string
fsDownloadDir: string
guiConfig: string
serverConfig: string
uses24HourClock: boolean
version: string
*/
}
getDefaultCountryCode(): Promise<string>
logSend(
Expand Down
24 changes: 13 additions & 11 deletions rnmodules/react-native-kb/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,16 @@ export const getNativeEmitter = () => {
return new NativeEventEmitter(Kb as any)
}

export const androidIsDeviceSecure: boolean = Kb.getConstants().androidIsDeviceSecure
export const androidIsTestDevice: boolean = Kb.getConstants().androidIsTestDevice
export const appVersionCode: string = Kb.getConstants().appVersionCode
export const appVersionName: string = Kb.getConstants().appVersionCode
export const darkModeSupported: boolean = Kb.getConstants().darkModeSupported
export const fsCacheDir: string = Kb.getConstants().fsCacheDir
export const fsDownloadDir: string = Kb.getConstants().fsDownloadDir
export const guiConfig: string = Kb.getConstants().guiConfig
export const serverConfig: string = Kb.getConstants().serverConfig
export const uses24HourClock: boolean = Kb.getConstants().uses24HourClock
export const version: string = Kb.getConstants().version
const pc = Kb.getTypedConstants()

export const androidIsDeviceSecure: boolean = pc.androidIsDeviceSecure
export const androidIsTestDevice: boolean = pc.androidIsTestDevice
export const appVersionCode: string = pc.appVersionCode
export const appVersionName: string = pc.appVersionCode
export const darkModeSupported: boolean = pc.darkModeSupported
export const fsCacheDir: string = pc.fsCacheDir
export const fsDownloadDir: string = pc.fsDownloadDir
export const guiConfig: string = pc.guiConfig
export const serverConfig: string = pc.serverConfig
export const uses24HourClock: boolean = pc.uses24HourClock
export const version: string = pc.version
3 changes: 2 additions & 1 deletion shared/android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
# to write custom TurboModules/Fabric components OR use libraries that
# are providing them.
# RUN A CLEAN if you change this
newArchEnabled=false # TEMP this is just due to https://github.com/software-mansion/react-native-screens/pull/2466 not being merged
# TEMP this is just due to https://github.com/software-mansion/react-native-screens/pull/2466 not being merged
newArchEnabled=false
# Use this property to enable or disable the Hermes JS engine.
# If set to false, you will be using JSC instead.
hermesEnabled=true
Expand Down
27 changes: 15 additions & 12 deletions shared/app/index.native.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,19 +101,22 @@ let inited = false
const useInit = () => {
if (inited) return
inited = true
const {batch} = C.useWaitingState.getState().dispatch
const eng = makeEngine(batch, c => {
if (c) {
C.useEngineState.getState().dispatch.onEngineConnected()
} else {
C.useEngineState.getState().dispatch.onEngineDisconnected()
}
})
C.initListeners()
eng.listenersAreReady()
const f = async () => {
const {batch} = C.useWaitingState.getState().dispatch
const eng = makeEngine(batch, c => {
if (c) {
C.useEngineState.getState().dispatch.onEngineConnected()
} else {
C.useEngineState.getState().dispatch.onEngineDisconnected()
}
})
await C.initListeners()
eng.listenersAreReady()

// On mobile there is no installer
C.useConfigState.getState().dispatch.installerRan()
// On mobile there is no installer
C.useConfigState.getState().dispatch.installerRan()
}
C.ignorePromise(f())
}

// reanimated has issues updating shared values with this on seemingly w/ zoom toolkit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const PopAttach = (ownProps: OwnProps) => {
}, [messageAttachmentNativeSave, ordinal])

const onSaveAttachment =
C.isMobile && (attachmentType === 'image' || C.Chat.isImageViewable(message))
(C.isMobile && (attachmentType === 'image' || C.Chat.isImageViewable(message))) || C.isAndroid
? _onSaveAttachment
: undefined

Expand Down
7 changes: 6 additions & 1 deletion shared/constants/chat2/convostate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1826,7 +1826,12 @@ const createSlice: Z.ImmerStateCreator<ConvoState> = (set, get) => {
}
})
logger.info('Trying to save chat attachment to camera roll')
await C.PlatformSpecific.saveAttachmentToCameraRoll(fileName, fileType)
const isCamera = fileType.startsWith('image/') || fileType.startsWith('video/')
if (isCamera) {
await C.PlatformSpecific.saveAttachmentToCameraRoll(fileName, fileType)
} else if (C.isAndroid) {
await C.PlatformSpecific.saveAttachmentToCameraRoll(fileName, fileType)
}
set(s => {
const m3 = s.messageMap.get(ordinal)
if (m3?.type === 'attachment') {
Expand Down
9 changes: 3 additions & 6 deletions shared/constants/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,9 @@ import {useConfigState_ as useConfigState} from './config'
export {default as shallowEqual} from 'shallowequal'
export * as PlatformSpecific from './platform-specific'

export const initListeners = () => {
const f = async () => {
await useFSState.getState().dispatch.setupSubscriptions()
useConfigState.getState().dispatch.setupSubscriptions()
}
ignorePromise(f())
export const initListeners = async () => {
await useFSState.getState().dispatch.setupSubscriptions()
useConfigState.getState().dispatch.setupSubscriptions()
}

// extracts the payload from pages used in routing
Expand Down
1 change: 1 addition & 0 deletions shared/constants/platform-specific/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export declare function showShareActionSheet(options: {
method: string
}>

export declare function saveAttachmentToMobile(fileURL: string, mimeType: string): Promise<void>
export declare function saveAttachmentToCameraRoll(fileURL: string, mimeType: string): Promise<void>
export declare function requestLocationPermission(mode: T.RPCChat.UIWatchPositionPerm): Promise<void>
export declare function watchPositionForMap(conversationIDKey: T.Chat.ConversationIDKey): Promise<() => void>
Expand Down
4 changes: 4 additions & 0 deletions shared/constants/platform-specific/index.desktop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ export async function saveAttachmentToCameraRoll() {
return Promise.reject(new Error('Save Attachment to camera roll - unsupported on this platform'))
}

export async function saveAttachmentToMobile() {
return Promise.reject(new Error('Save Attachment to mobile- unsupported on this platform'))
}

export const requestLocationPermission = async () => Promise.resolve()
export const watchPositionForMap = async () => Promise.resolve(() => {})

Expand Down
36 changes: 24 additions & 12 deletions shared/constants/platform-specific/index.native.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ export const requestLocationPermission = async (mode: T.RPCChat.UIWatchPositionP
}
}

export async function saveAttachmentToMobile(filePath: string, mimeType: string): Promise<void> {}

export async function saveAttachmentToCameraRoll(filePath: string, mimeType: string): Promise<void> {
const fileURL = 'file://' + filePath
const saveType: 'video' | 'photo' = mimeType.startsWith('video') ? 'video' : 'photo'
Expand All @@ -76,7 +78,18 @@ export async function saveAttachmentToCameraRoll(filePath: string, mimeType: str
await requestPermissionsToWrite()
} catch {}
logger.info(logPrefix + `Attempting to save as ${saveType}`)
await MediaLibrary.saveToLibraryAsync(fileURL)
if (isIOS) {
await MediaLibrary.saveToLibraryAsync(fileURL)
} else {
const asset = await MediaLibrary.createAssetAsync(fileURL)
const albumName = 'Keybase'
const _album = await MediaLibrary.getAlbumAsync(albumName)
let album = _album as typeof _album | null
if (!album) {
album = await MediaLibrary.createAlbumAsync(albumName, asset, false)
}
await MediaLibrary.addAssetsToAlbumAsync([asset], album, false)
}
logger.info(logPrefix + 'Success')
} catch (e) {
// This can fail if the user backgrounds too quickly, so throw up a local notification
Expand Down Expand Up @@ -414,6 +427,16 @@ export const initPlatformListener = () => {
})

C.useDaemonState.subscribe((s, old) => {
if (isAndroid) {
C.ignorePromise(
T.RPCChat.localConfigureFileAttachmentDownloadLocalRpcPromise({
// Android's cache dir is (when I tried) [app]/cache but Go side uses
// [app]/.cache by default, which can't be used for sharing to other apps.
cacheDirOverride: fsCacheDir,
downloadDirOverride: fsDownloadDir,
})
)
}
if (s.handshakeVersion === old.handshakeVersion) return

// loadStartupDetails finished already
Expand All @@ -429,17 +452,6 @@ export const initPlatformListener = () => {
}
afterStartupDetails(true)
}

if (isAndroid) {
C.ignorePromise(
T.RPCChat.localConfigureFileAttachmentDownloadLocalRpcPromise({
// Android's cache dir is (when I tried) [app]/cache but Go side uses
// [app]/.cache by default, which can't be used for sharing to other apps.
cacheDirOverride: fsCacheDir,
downloadDirOverride: fsDownloadDir,
})
)
}
})

C.useConfigState.setState(s => {
Expand Down
1 change: 1 addition & 0 deletions shared/engine/index-impl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ class Engine {
// We proxy the stuff over the mainWindowDispatch
_onConnected() {
this._hasConnected = true

this._onConnectedCB(true)
}

Expand Down
7 changes: 7 additions & 0 deletions shared/todo.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
chat file save flows
click on pdf insta saves with a quick blink of the save overlay?
kbfs save flows




TEMP disabling new arch on android due to this
android can't click on stack header area in new arch: https://github.com/software-mansion/react-native-screens/pull/2466

Expand Down