mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-07-04 13:23:28 +00:00
Onboarding, Spacedrop & Location Settings Screen & Styled API (#596)
* fix wrong current lib logic * add delete lib dialog to LibraryGeneralSettings * add delete lib to mobile LibraryGeneralSettings too * onboarding screens * move zxcvbn to @sd/client * get started screen and bloom * merge fix * move generatePassword back to interface * add useZodForm to mobile and match react-hook-form versions * new lib screen * Implement styled api * create lib screen and some tweaks * password input * fix password meter comp * new library style tweaks * Fix remove password bug (interface) * master password screen * privacy screen * creating lib screen * hexagons are cool * Expo 48 * keyboard handling * fix P2P on IOS * fix types * asset script * new icons * Spacedrop screen * Fix mobile asset imports * fix import cycle warning * Edit Location Settings screen and style changes on other setting screens * fix library creating bug? hopefully lol * move PasswordMeter to interface --------- Co-authored-by: Oscar Beaumont <oscar@otbeaumont.me>
This commit is contained in:
parent
3b4248c836
commit
902a3b5ba1
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"*.{js,jsx,ts,tsx,html,json,yml,yaml,css,scss,md}": ["prettier --write"]
|
||||
}
|
12
.vscode/settings.json
vendored
12
.vscode/settings.json
vendored
|
@ -38,12 +38,12 @@
|
|||
"rust-analyzer.procMacro.enable": true,
|
||||
"rust-analyzer.diagnostics.experimental.enable": false,
|
||||
"tailwindCSS.experimental.classRegex": [
|
||||
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"],
|
||||
"tw`([^`]*)",
|
||||
"tw\\.[^`]+`([^`]*)`",
|
||||
"tw\\(.*?\\).*?`([^`]*)",
|
||||
"tw\\.style\\(([^)]*)\\)",
|
||||
"twStyle\\(([^)]*)\\)"
|
||||
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"], // cva(....)`...`
|
||||
"tw\\.[^`]+`([^`]*)`", // tw.xxx`...`
|
||||
"tw\\(.*?\\).*?`([^`]*)", // tw(....)`...`
|
||||
"tw`([^`]*)", // tw`...` (mobile)
|
||||
"twStyle\\(([^)]*)\\)", // twStyle(....) (mobile)
|
||||
["styled\\([^,)]+,([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"] // styled(....)`...` (mobile)
|
||||
],
|
||||
"search.exclude": {
|
||||
"**/node_modules": true,
|
||||
|
|
|
@ -69,12 +69,12 @@ To run mobile app
|
|||
|
||||
- Install [Android Studio](https://developer.android.com/studio) for Android and [Xcode](https://apps.apple.com/au/app/xcode/id497799835) for IOS development
|
||||
- `./.github/scripts/setup-system.sh mobile`
|
||||
|
||||
- The should setup most of the dependencies for the mobile app to build.
|
||||
- You must also ensure [you must have NDK 24.0.8215888 and CMake](https://developer.android.com/studio/projects/install-ndk#default-version) in Android Studio
|
||||
- `cd apps/mobile && pnpm i` - This is a separate workspace, you need to do this!
|
||||
|
||||
- You must also ensure [you must have NDK 23.1.7779620 and CMake](https://developer.android.com/studio/projects/install-ndk#default-version) in Android Studio
|
||||
- `pnpm android` - runs on Android Emulator
|
||||
- `pnpm ios` - runs on iOS Emulator
|
||||
- `pnpm start` - For already bundled app
|
||||
|
||||
### Pull Request
|
||||
|
||||
|
|
5
Cargo.lock
generated
5
Cargo.lock
generated
|
@ -3130,8 +3130,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "if-watch"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba7abdbb86e485125dad06c2691e1e393bf3b08c7b743b43aa162a00fd39062e"
|
||||
source = "git+https://github.com/oscartbeaumont/if-watch?rev=410e8e1d2d0730f1441df1c29294fec4c3c04193#410e8e1d2d0730f1441df1c29294fec4c3c04193"
|
||||
dependencies = [
|
||||
"async-io",
|
||||
"core-foundation",
|
||||
|
@ -4081,7 +4080,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "mdns-sd"
|
||||
version = "0.6.1"
|
||||
source = "git+https://github.com/oscartbeaumont/mdns-sd.git?rev=45515a98e9e408c102871abaa5a9bff3bee0cbe8#45515a98e9e408c102871abaa5a9bff3bee0cbe8"
|
||||
source = "git+https://github.com/oscartbeaumont/mdns-sd?rev=45515a98e9e408c102871abaa5a9bff3bee0cbe8#45515a98e9e408c102871abaa5a9bff3bee0cbe8"
|
||||
dependencies = [
|
||||
"flume",
|
||||
"if-addrs",
|
||||
|
|
|
@ -40,8 +40,10 @@ tokio = { version = "1.25.0" }
|
|||
[patch.crates-io]
|
||||
# We use this patch so we can compile for the IOS simulator on M1
|
||||
openssl-sys = { git = "https://github.com/spacedriveapp/rust-openssl", rev = "92c3dec225a9e984884d5b30a517e5d44a24d03b" }
|
||||
# We patch this so that it can be built for IOS - The `main` branch uses macOS specific APIs
|
||||
if-watch = { git = "https://github.com/oscartbeaumont/if-watch", rev = "410e8e1d2d0730f1441df1c29294fec4c3c04193" }
|
||||
|
||||
mdns-sd = { git = "https://github.com/oscartbeaumont/mdns-sd.git", rev = "45515a98e9e408c102871abaa5a9bff3bee0cbe8" } # TODO: Do upstream PR
|
||||
mdns-sd = { git = "https://github.com/oscartbeaumont/mdns-sd", rev = "45515a98e9e408c102871abaa5a9bff3bee0cbe8" } # TODO: Do upstream PR
|
||||
|
||||
rspc = { git = "https://github.com/oscartbeaumont/rspc", rev = "c03872c0ba29d2429e9c059dfb235cdd03e15e8c" } # TODO: Move back to crates.io when new jsonrpc executor + `tokio::spawn` in the Tauri IPC plugin + upgraded Tauri version is released
|
||||
specta = { git = "https://github.com/oscartbeaumont/rspc", rev = "c03872c0ba29d2429e9c059dfb235cdd03e15e8c" }
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
"react-burger-menu": "^3.0.8",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-hook-form": "^7.36.1",
|
||||
"react-hook-form": "^7.43.5",
|
||||
"react-tsparticles": "^2.3.3",
|
||||
"sirv": "^2.0.2",
|
||||
"ts-node": "^10.9.1",
|
||||
|
|
9
apps/mobile/.gitignore
vendored
9
apps/mobile/.gitignore
vendored
|
@ -37,12 +37,6 @@ node_modules/
|
|||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# BUCK
|
||||
buck-out/
|
||||
\.buckd/
|
||||
*.keystore
|
||||
!debug.keystore
|
||||
|
||||
# Bundle artifacts
|
||||
*.jsbundle
|
||||
|
||||
|
@ -53,3 +47,6 @@ buck-out/
|
|||
.expo/
|
||||
web-build/
|
||||
dist/
|
||||
|
||||
# Temporary files created by Metro to check the health of the file watcher
|
||||
.metro-health-check*
|
8
apps/mobile/android/.gitignore
vendored
8
apps/mobile/android/.gitignore
vendored
|
@ -11,11 +11,5 @@ local.properties
|
|||
*.iml
|
||||
*.hprof
|
||||
|
||||
# BUCK
|
||||
buck-out/
|
||||
\.buckd/
|
||||
*.keystore
|
||||
!debug.keystore
|
||||
|
||||
# Bundle artifacts
|
||||
*.jsbundle
|
||||
*.jsbundle
|
|
@ -1,55 +0,0 @@
|
|||
# To learn about Buck see [Docs](https://buckbuild.com/).
|
||||
# To run your application with Buck:
|
||||
# - install Buck
|
||||
# - `npm start` - to start the packager
|
||||
# - `cd android`
|
||||
# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
|
||||
# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
|
||||
# - `buck install -r android/app` - compile, install and run application
|
||||
#
|
||||
|
||||
load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")
|
||||
|
||||
lib_deps = []
|
||||
|
||||
create_aar_targets(glob(["libs/*.aar"]))
|
||||
|
||||
create_jar_targets(glob(["libs/*.jar"]))
|
||||
|
||||
android_library(
|
||||
name = "all-libs",
|
||||
exported_deps = lib_deps,
|
||||
)
|
||||
|
||||
android_library(
|
||||
name = "app-code",
|
||||
srcs = glob([
|
||||
"src/main/java/**/*.java",
|
||||
]),
|
||||
deps = [
|
||||
":all-libs",
|
||||
":build_config",
|
||||
":res",
|
||||
],
|
||||
)
|
||||
|
||||
android_build_config(
|
||||
name = "build_config",
|
||||
package = "com.spacedrive.app",
|
||||
)
|
||||
|
||||
android_resource(
|
||||
name = "res",
|
||||
package = "com.spacedrive.app",
|
||||
res = "src/main/res",
|
||||
)
|
||||
|
||||
android_binary(
|
||||
name = "app",
|
||||
keystore = "//android/keystores:debug",
|
||||
manifest = "src/main/AndroidManifest.xml",
|
||||
package_type = "debug",
|
||||
deps = [
|
||||
":app-code",
|
||||
],
|
||||
)
|
|
@ -1,8 +1,10 @@
|
|||
apply plugin: "com.android.application"
|
||||
apply plugin: "com.facebook.react"
|
||||
|
||||
import com.android.build.OutputFile
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
|
||||
|
||||
// SPACEDRIVE CODE
|
||||
apply plugin: 'org.mozilla.rust-android-gradle.rust-android'
|
||||
|
||||
cargo {
|
||||
|
@ -23,134 +25,108 @@ tasks.whenTaskAdded { task ->
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
|
||||
* and bundleReleaseJsAndAssets).
|
||||
* These basically call `react-native bundle` with the correct arguments during the Android build
|
||||
* cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
|
||||
* bundle directly from the development server. Below you can see all the possible configurations
|
||||
* and their defaults. If you decide to add a configuration block, make sure to add it before the
|
||||
* `apply from: "../../node_modules/react-native/react.gradle"` line.
|
||||
*
|
||||
* project.ext.react = [
|
||||
* // the name of the generated asset file containing your JS bundle
|
||||
* bundleAssetName: "index.android.bundle",
|
||||
*
|
||||
* // the entry file for bundle generation. If none specified and
|
||||
* // "index.android.js" exists, it will be used. Otherwise "index.js" is
|
||||
* // default. Can be overridden with ENTRY_FILE environment variable.
|
||||
* entryFile: "index.android.js",
|
||||
*
|
||||
* // https://reactnative.dev/docs/performance#enable-the-ram-format
|
||||
* bundleCommand: "ram-bundle",
|
||||
*
|
||||
* // whether to bundle JS and assets in debug mode
|
||||
* bundleInDebug: false,
|
||||
*
|
||||
* // whether to bundle JS and assets in release mode
|
||||
* bundleInRelease: true,
|
||||
*
|
||||
* // whether to bundle JS and assets in another build variant (if configured).
|
||||
* // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
|
||||
* // The configuration property can be in the following formats
|
||||
* // 'bundleIn${productFlavor}${buildType}'
|
||||
* // 'bundleIn${buildType}'
|
||||
* // bundleInFreeDebug: true,
|
||||
* // bundleInPaidRelease: true,
|
||||
* // bundleInBeta: true,
|
||||
*
|
||||
* // whether to disable dev mode in custom build variants (by default only disabled in release)
|
||||
* // for example: to disable dev mode in the staging build type (if configured)
|
||||
* devDisabledInStaging: true,
|
||||
* // The configuration property can be in the following formats
|
||||
* // 'devDisabledIn${productFlavor}${buildType}'
|
||||
* // 'devDisabledIn${buildType}'
|
||||
*
|
||||
* // the root of your project, i.e. where "package.json" lives
|
||||
* root: "../../",
|
||||
*
|
||||
* // where to put the JS bundle asset in debug mode
|
||||
* jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
|
||||
*
|
||||
* // where to put the JS bundle asset in release mode
|
||||
* jsBundleDirRelease: "$buildDir/intermediates/assets/release",
|
||||
*
|
||||
* // where to put drawable resources / React Native assets, e.g. the ones you use via
|
||||
* // require('./image.png')), in debug mode
|
||||
* resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
|
||||
*
|
||||
* // where to put drawable resources / React Native assets, e.g. the ones you use via
|
||||
* // require('./image.png')), in release mode
|
||||
* resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
|
||||
*
|
||||
* // by default the gradle tasks are skipped if none of the JS files or assets change; this means
|
||||
* // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
|
||||
* // date; if you have any other folders that you want to ignore for performance reasons (gradle
|
||||
* // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
|
||||
* // for example, you might want to remove it from here.
|
||||
* inputExcludes: ["android/**", "ios/**"],
|
||||
*
|
||||
* // override which node gets called and with what additional arguments
|
||||
* nodeExecutableAndArgs: ["node"],
|
||||
*
|
||||
* // supply additional arguments to the packager
|
||||
* extraPackagerArgs: []
|
||||
* ]
|
||||
*/
|
||||
// SPACEDRIVE CODE END
|
||||
|
||||
def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath()
|
||||
def expoDebuggableVariants = ['debug']
|
||||
// Override `debuggableVariants` for expo-updates debugging
|
||||
if (System.getenv('EX_UPDATES_NATIVE_DEBUG') == "1") {
|
||||
react {
|
||||
expoDebuggableVariants = []
|
||||
}
|
||||
}
|
||||
|
||||
def reactNativeRoot = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath()
|
||||
|
||||
project.ext.react = [
|
||||
entryFile: ["node", "-e", "require('expo/scripts/resolveAppEntry')", projectRoot, "android"].execute(null, rootDir).text.trim(),
|
||||
enableHermes: (findProperty('expo.jsEngine') ?: "jsc") == "hermes",
|
||||
hermesCommand: new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/sdks/hermesc/%OS-BIN%/hermesc",
|
||||
cliPath: "${reactNativeRoot}/cli.js",
|
||||
composeSourceMapsPath: "${reactNativeRoot}/scripts/compose-source-maps.js",
|
||||
]
|
||||
|
||||
apply from: new File(reactNativeRoot, "react.gradle")
|
||||
|
||||
/**
|
||||
* Set this to true to create two separate APKs instead of one:
|
||||
* - An APK that only works on ARM devices
|
||||
* - An APK that only works on x86 devices
|
||||
* The advantage is the size of the APK is reduced by about 4MB.
|
||||
* Upload all the APKs to the Play Store and people will download
|
||||
* the correct one based on the CPU architecture of their device.
|
||||
* This is the configuration block to customize your React Native Android app.
|
||||
* By default you don't need to apply any configuration, just uncomment the lines you need.
|
||||
*/
|
||||
react {
|
||||
entryFile = file(["node", "-e", "require('expo/scripts/resolveAppEntry')", projectRoot, "android", "absolute"].execute(null, rootDir).text.trim())
|
||||
reactNativeDir = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()
|
||||
hermesCommand = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/sdks/hermesc/%OS-BIN%/hermesc"
|
||||
debuggableVariants = expoDebuggableVariants
|
||||
|
||||
// Use Expo CLI to bundle the app, this ensures the Metro config
|
||||
// works correctly with Expo projects.
|
||||
cliFile = new File(["node", "--print", "require.resolve('@expo/cli')"].execute(null, rootDir).text.trim())
|
||||
bundleCommand = "export:embed"
|
||||
|
||||
/* Folders */
|
||||
// The root of your project, i.e. where "package.json" lives. Default is '..'
|
||||
// root = file("../")
|
||||
// The folder where the react-native NPM package is. Default is ../node_modules/react-native
|
||||
// reactNativeDir = file("../node_modules/react-native")
|
||||
// The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen
|
||||
// codegenDir = file("../node_modules/react-native-codegen")
|
||||
|
||||
/* Variants */
|
||||
// The list of variants to that are debuggable. For those we're going to
|
||||
// skip the bundling of the JS bundle and the assets. By default is just 'debug'.
|
||||
// If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
|
||||
// debuggableVariants = ["liteDebug", "prodDebug"]
|
||||
|
||||
/* Bundling */
|
||||
// A list containing the node command and its flags. Default is just 'node'.
|
||||
// nodeExecutableAndArgs = ["node"]
|
||||
|
||||
//
|
||||
// The path to the CLI configuration file. Default is empty.
|
||||
// bundleConfig = file(../rn-cli.config.js)
|
||||
//
|
||||
// The name of the generated asset file containing your JS bundle
|
||||
// bundleAssetName = "MyApplication.android.bundle"
|
||||
//
|
||||
// The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
|
||||
// entryFile = file("../js/MyApplication.android.js")
|
||||
//
|
||||
// A list of extra flags to pass to the 'bundle' commands.
|
||||
// See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
|
||||
// extraPackagerArgs = []
|
||||
|
||||
/* Hermes Commands */
|
||||
// The hermes compiler command to run. By default it is 'hermesc'
|
||||
// hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
|
||||
//
|
||||
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
|
||||
// hermesFlags = ["-O", "-output-source-map"]
|
||||
}
|
||||
|
||||
// Override `hermesEnabled` by `expo.jsEngine`
|
||||
ext {
|
||||
hermesEnabled = (findProperty('expo.jsEngine') ?: "hermes") == "hermes"
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this to true to create four separate APKs instead of one,
|
||||
* one for each native architecture. This is useful if you don't
|
||||
* use App Bundles (https://developer.android.com/guide/app-bundle/)
|
||||
* and want to have separate APKs to upload to the Play Store.
|
||||
*/
|
||||
def enableSeparateBuildPerCPUArchitecture = false
|
||||
|
||||
/**
|
||||
* Run Proguard to shrink the Java bytecode in release builds.
|
||||
* Set this to true to Run Proguard on Release builds to minify the Java bytecode.
|
||||
*/
|
||||
def enableProguardInReleaseBuilds = (findProperty('android.enableProguardInReleaseBuilds') ?: false).toBoolean()
|
||||
|
||||
/**
|
||||
* The preferred build flavor of JavaScriptCore.
|
||||
* The preferred build flavor of JavaScriptCore (JSC)
|
||||
*
|
||||
* For example, to use the international variant, you can use:
|
||||
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
|
||||
*
|
||||
* The international variant includes ICU i18n library and necessary data
|
||||
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
|
||||
* give correct results when using with locales other than en-US. Note that
|
||||
* give correct results when using with locales other than en-US. Note that
|
||||
* this variant is about 6MiB larger per architecture than default.
|
||||
*/
|
||||
def jscFlavor = 'org.webkit:android-jsc:+'
|
||||
|
||||
/**
|
||||
* Whether to enable the Hermes VM.
|
||||
*
|
||||
* This should be set on project.ext.react and that value will be read here. If it is not set
|
||||
* on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
|
||||
* and the benefits of using Hermes will therefore be sharply reduced.
|
||||
*/
|
||||
def enableHermes = project.ext.react.get("enableHermes", false);
|
||||
|
||||
/**
|
||||
* Architectures to build native code for.
|
||||
* Private function to get the list of Native Architectures you want to build.
|
||||
* This reads the value from reactNativeArchitectures in your gradle.properties
|
||||
* file and works together with the --active-arch-only flag of react-native run-android.
|
||||
*/
|
||||
def reactNativeArchitectures() {
|
||||
def value = project.getProperties().get("reactNativeArchitectures")
|
||||
|
@ -163,84 +139,11 @@ android {
|
|||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
|
||||
defaultConfig {
|
||||
applicationId 'com.spacedrive.app'
|
||||
applicationId "com.spacedrive.app"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 1
|
||||
versionName "0.0.1"
|
||||
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
|
||||
|
||||
if (isNewArchitectureEnabled()) {
|
||||
// We configure the NDK build only if you decide to opt-in for the New Architecture.
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
arguments "APP_PLATFORM=android-21",
|
||||
"APP_STL=c++_shared",
|
||||
"NDK_TOOLCHAIN_VERSION=clang",
|
||||
"GENERATED_SRC_DIR=$buildDir/generated/source",
|
||||
"PROJECT_BUILD_DIR=$buildDir",
|
||||
"REACT_ANDROID_DIR=${reactNativeRoot}/ReactAndroid",
|
||||
"REACT_ANDROID_BUILD_DIR=${reactNativeRoot}/ReactAndroid/build",
|
||||
"NODE_MODULES_DIR=$rootDir/../node_modules"
|
||||
cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
|
||||
cppFlags "-std=c++17"
|
||||
// Make sure this target name is the same you specify inside the
|
||||
// src/main/jni/Android.mk file for the `LOCAL_MODULE` variable.
|
||||
targets "spacedrive_appmodules"
|
||||
|
||||
// Fix for windows limit on number of character in file paths and in command lines
|
||||
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||
arguments "NDK_APP_SHORT_COMMANDS=true"
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!enableSeparateBuildPerCPUArchitecture) {
|
||||
ndk {
|
||||
abiFilters (*reactNativeArchitectures())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isNewArchitectureEnabled()) {
|
||||
// We configure the NDK build only if you decide to opt-in for the New Architecture.
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
path "$projectDir/src/main/jni/Android.mk"
|
||||
}
|
||||
}
|
||||
def reactAndroidProjectDir = project(':ReactAndroid').projectDir
|
||||
def packageReactNdkDebugLibs = tasks.register("packageReactNdkDebugLibs", Copy) {
|
||||
dependsOn(":ReactAndroid:packageReactNdkDebugLibsForBuck")
|
||||
from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
|
||||
into("$buildDir/react-ndk/exported")
|
||||
}
|
||||
def packageReactNdkReleaseLibs = tasks.register("packageReactNdkReleaseLibs", Copy) {
|
||||
dependsOn(":ReactAndroid:packageReactNdkReleaseLibsForBuck")
|
||||
from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
|
||||
into("$buildDir/react-ndk/exported")
|
||||
}
|
||||
afterEvaluate {
|
||||
// If you wish to add a custom TurboModule or component locally,
|
||||
// you should uncomment this line.
|
||||
// preBuild.dependsOn("generateCodegenArtifactsFromSchema")
|
||||
preDebugBuild.dependsOn(packageReactNdkDebugLibs)
|
||||
preReleaseBuild.dependsOn(packageReactNdkReleaseLibs)
|
||||
|
||||
// Due to a bug inside AGP, we have to explicitly set a dependency
|
||||
// between configureNdkBuild* tasks and the preBuild tasks.
|
||||
// This can be removed once this is solved: https://issuetracker.google.com/issues/207403732
|
||||
configureNdkBuildRelease.dependsOn(preReleaseBuild)
|
||||
configureNdkBuildDebug.dependsOn(preDebugBuild)
|
||||
reactNativeArchitectures().each { architecture ->
|
||||
tasks.findByName("configureNdkBuildDebug[${architecture}]")?.configure {
|
||||
dependsOn("preDebugBuild")
|
||||
}
|
||||
tasks.findByName("configureNdkBuildRelease[${architecture}]")?.configure {
|
||||
dependsOn("preReleaseBuild")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
splits {
|
||||
|
@ -277,11 +180,12 @@ android {
|
|||
variant.outputs.each { output ->
|
||||
// For each separate APK per architecture, set a unique version code as described here:
|
||||
// https://developer.android.com/studio/build/configure-apk-splits.html
|
||||
// Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc.
|
||||
def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
|
||||
def abi = output.getFilter(OutputFile.ABI)
|
||||
if (abi != null) { // null for the universal-debug, universal-release variants
|
||||
output.versionCodeOverride =
|
||||
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
|
||||
defaultConfig.versionCode * 1000 + versionCodes.get(abi)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -309,10 +213,8 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
|
||||
//noinspection GradleDynamicVersion
|
||||
implementation "com.facebook.react:react-native:+" // From node_modules
|
||||
// The version of react-native is set by the React Native Gradle Plugin
|
||||
implementation("com.facebook.react:react-android")
|
||||
|
||||
def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true";
|
||||
def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true";
|
||||
|
@ -321,76 +223,38 @@ dependencies {
|
|||
|
||||
// If your app supports Android versions before Ice Cream Sandwich (API level 14)
|
||||
if (isGifEnabled || isWebpEnabled) {
|
||||
implementation "com.facebook.fresco:fresco:${frescoVersion}"
|
||||
implementation "com.facebook.fresco:imagepipeline-okhttp3:${frescoVersion}"
|
||||
implementation("com.facebook.fresco:fresco:${frescoVersion}")
|
||||
implementation("com.facebook.fresco:imagepipeline-okhttp3:${frescoVersion}")
|
||||
}
|
||||
|
||||
if (isGifEnabled) {
|
||||
// For animated gif support
|
||||
implementation "com.facebook.fresco:animated-gif:${frescoVersion}"
|
||||
implementation("com.facebook.fresco:animated-gif:${frescoVersion}")
|
||||
}
|
||||
|
||||
if (isWebpEnabled) {
|
||||
// For webp support
|
||||
implementation "com.facebook.fresco:webpsupport:${frescoVersion}"
|
||||
implementation("com.facebook.fresco:webpsupport:${frescoVersion}")
|
||||
if (isWebpAnimatedEnabled) {
|
||||
// Animated webp support
|
||||
implementation "com.facebook.fresco:animated-webp:${frescoVersion}"
|
||||
implementation("com.facebook.fresco:animated-webp:${frescoVersion}")
|
||||
}
|
||||
}
|
||||
|
||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
|
||||
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
|
||||
exclude group:'com.facebook.fbjni'
|
||||
}
|
||||
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0")
|
||||
|
||||
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}")
|
||||
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
|
||||
exclude group:'com.facebook.flipper'
|
||||
exclude group:'com.squareup.okhttp3', module:'okhttp'
|
||||
}
|
||||
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
|
||||
exclude group:'com.facebook.flipper'
|
||||
}
|
||||
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}")
|
||||
|
||||
if (enableHermes) {
|
||||
//noinspection GradleDynamicVersion
|
||||
implementation("com.facebook.react:hermes-engine:+") { // From node_modules
|
||||
exclude group:'com.facebook.fbjni'
|
||||
}
|
||||
if (hermesEnabled.toBoolean()) {
|
||||
implementation("com.facebook.react:hermes-android")
|
||||
} else {
|
||||
implementation jscFlavor
|
||||
}
|
||||
}
|
||||
|
||||
if (isNewArchitectureEnabled()) {
|
||||
// If new architecture is enabled, we let you build RN from source
|
||||
// Otherwise we fallback to a prebuilt .aar bundled in the NPM package.
|
||||
// This will be applied to all the imported transtitive dependency.
|
||||
configurations.all {
|
||||
resolutionStrategy.dependencySubstitution {
|
||||
substitute(module("com.facebook.react:react-native"))
|
||||
.using(project(":ReactAndroid"))
|
||||
.because("On New Architecture we're building React Native from source")
|
||||
substitute(module("com.facebook.react:hermes-engine"))
|
||||
.using(project(":ReactAndroid:hermes-engine"))
|
||||
.because("On New Architecture we're building Hermes from source")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run this once to be able to run the application with BUCK
|
||||
// puts all compile dependencies into folder libs for BUCK to use
|
||||
task copyDownloadableDepsToLibs(type: Copy) {
|
||||
from configurations.implementation
|
||||
into 'libs'
|
||||
}
|
||||
|
||||
apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json')"].execute(null, rootDir).text.trim(), "../native_modules.gradle");
|
||||
applyNativeModulesAppBuildGradle(project)
|
||||
|
||||
def isNewArchitectureEnabled() {
|
||||
// To opt-in for the New Architecture, you can either:
|
||||
// - Set `newArchEnabled` to true inside the `gradle.properties` file
|
||||
// - Invoke gradle with `-newArchEnabled=true`
|
||||
// - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
|
||||
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
|
||||
}
|
||||
applyNativeModulesAppBuildGradle(project)
|
|
@ -1,19 +0,0 @@
|
|||
"""Helper definitions to glob .aar and .jar targets"""
|
||||
|
||||
def create_aar_targets(aarfiles):
|
||||
for aarfile in aarfiles:
|
||||
name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")]
|
||||
lib_deps.append(":" + name)
|
||||
android_prebuilt_aar(
|
||||
name = name,
|
||||
aar = aarfile,
|
||||
)
|
||||
|
||||
def create_jar_targets(jarfiles):
|
||||
for jarfile in jarfiles:
|
||||
name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")]
|
||||
lib_deps.append(":" + name)
|
||||
prebuilt_jar(
|
||||
name = name,
|
||||
binary_jar = jarfile,
|
||||
)
|
2
apps/mobile/android/app/proguard-rules.pro
vendored
2
apps/mobile/android/app/proguard-rules.pro
vendored
|
@ -11,4 +11,4 @@
|
|||
-keep class com.swmansion.reanimated.** { *; }
|
||||
-keep class com.facebook.react.turbomodule.** { *; }
|
||||
|
||||
# Add any project specific keep options here:
|
||||
# Add any project specific keep options here:
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
|
||||
* directory of this source tree.
|
||||
|
@ -17,22 +17,27 @@ import com.facebook.flipper.plugins.inspector.DescriptorMapping;
|
|||
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
|
||||
import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
|
||||
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
|
||||
import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
|
||||
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
|
||||
import com.facebook.react.ReactInstanceEventListener;
|
||||
import com.facebook.react.ReactInstanceManager;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.modules.network.NetworkingModule;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
/**
|
||||
* Class responsible of loading Flipper inside your React Native application. This is the debug
|
||||
* flavor of it. Here you can add your own plugins and customize the Flipper setup.
|
||||
*/
|
||||
public class ReactNativeFlipper {
|
||||
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
|
||||
if (FlipperUtils.shouldEnableFlipper(context)) {
|
||||
final FlipperClient client = AndroidFlipperClient.getInstance(context);
|
||||
|
||||
client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
|
||||
client.addPlugin(new ReactFlipperPlugin());
|
||||
client.addPlugin(new DatabasesFlipperPlugin(context));
|
||||
client.addPlugin(new SharedPreferencesFlipperPlugin(context));
|
||||
client.addPlugin(CrashReporterPlugin.getInstance());
|
||||
|
||||
NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
|
||||
NetworkingModule.setCustomClientBuilder(
|
||||
new NetworkingModule.CustomClientBuilder() {
|
||||
|
@ -43,12 +48,13 @@ public class ReactNativeFlipper {
|
|||
});
|
||||
client.addPlugin(networkFlipperPlugin);
|
||||
client.start();
|
||||
|
||||
// Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
|
||||
// Hence we run if after all native modules have been initialized
|
||||
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
|
||||
if (reactContext == null) {
|
||||
reactInstanceManager.addReactInstanceEventListener(
|
||||
new ReactInstanceManager.ReactInstanceEventListener() {
|
||||
new ReactInstanceEventListener() {
|
||||
@Override
|
||||
public void onReactContextInitialized(ReactContext reactContext) {
|
||||
reactInstanceManager.removeReactInstanceEventListener(this);
|
||||
|
|
|
@ -5,7 +5,8 @@ import android.os.Bundle;
|
|||
|
||||
import com.facebook.react.ReactActivity;
|
||||
import com.facebook.react.ReactActivityDelegate;
|
||||
import com.facebook.react.ReactRootView;
|
||||
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
|
||||
import com.facebook.react.defaults.DefaultReactActivityDelegate;
|
||||
|
||||
import expo.modules.ReactActivityDelegateWrapper;
|
||||
|
||||
|
@ -29,15 +30,20 @@ public class MainActivity extends ReactActivity {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and
|
||||
* you can specify the renderer you wish to use - the new renderer (Fabric) or the old renderer
|
||||
* (Paper).
|
||||
* Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link
|
||||
* DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React
|
||||
* (aka React 18) with two boolean flags.
|
||||
*/
|
||||
@Override
|
||||
protected ReactActivityDelegate createReactActivityDelegate() {
|
||||
return new ReactActivityDelegateWrapper(this, BuildConfig.IS_NEW_ARCHITECTURE_ENABLED,
|
||||
new MainActivityDelegate(this, getMainComponentName())
|
||||
);
|
||||
return new ReactActivityDelegateWrapper(this, BuildConfig.IS_NEW_ARCHITECTURE_ENABLED, new DefaultReactActivityDelegate(
|
||||
this,
|
||||
getMainComponentName(),
|
||||
// If you opted-in for the New Architecture, we enable the Fabric Renderer.
|
||||
DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled
|
||||
// If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18).
|
||||
DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -59,25 +65,4 @@ public class MainActivity extends ReactActivity {
|
|||
// because it's doing more than {@link Activity#moveTaskToBack} in fact.
|
||||
super.invokeDefaultOnBackPressed();
|
||||
}
|
||||
|
||||
public static class MainActivityDelegate extends ReactActivityDelegate {
|
||||
public MainActivityDelegate(ReactActivity activity, String mainComponentName) {
|
||||
super(activity, mainComponentName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReactRootView createRootView() {
|
||||
ReactRootView reactRootView = new ReactRootView(getContext());
|
||||
// If you opted-in for the New Architecture, we enable the Fabric Renderer.
|
||||
reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED);
|
||||
return reactRootView;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isConcurrentRootEnabled() {
|
||||
// If you opted-in for the New Architecture, we enable Concurrent Root (i.e. React 18).
|
||||
// More on this on https://reactjs.org/blog/2022/03/29/react-v18.html
|
||||
return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,69 +1,70 @@
|
|||
package com.spacedrive.app;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.facebook.react.PackageList;
|
||||
import com.facebook.react.ReactApplication;
|
||||
import com.facebook.react.ReactInstanceManager;
|
||||
import com.facebook.react.ReactNativeHost;
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.config.ReactFeatureFlags;
|
||||
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
|
||||
import com.facebook.react.defaults.DefaultReactNativeHost;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
import com.spacedrive.app.newarchitecture.MainApplicationReactNativeHost;
|
||||
|
||||
import expo.modules.ApplicationLifecycleDispatcher;
|
||||
import expo.modules.ReactNativeHostWrapper;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.List;
|
||||
|
||||
public class MainApplication extends Application implements ReactApplication {
|
||||
private final ReactNativeHost mReactNativeHost = new ReactNativeHostWrapper(
|
||||
this,
|
||||
new ReactNativeHost(this) {
|
||||
@Override
|
||||
public boolean getUseDeveloperSupport() {
|
||||
return BuildConfig.DEBUG;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ReactPackage> getPackages() {
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
List<ReactPackage> packages = new PackageList(this).getPackages();
|
||||
// Packages that cannot be autolinked yet can be added manually here, for example:
|
||||
packages.add(new com.spacedrive.app.SpacedrivePackage());
|
||||
return packages;
|
||||
}
|
||||
private final ReactNativeHost mReactNativeHost =
|
||||
new ReactNativeHostWrapper(this, new DefaultReactNativeHost(this) {
|
||||
@Override
|
||||
public boolean getUseDeveloperSupport() {
|
||||
return BuildConfig.DEBUG;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getJSMainModuleName() {
|
||||
return "index";
|
||||
}
|
||||
@Override
|
||||
protected List<ReactPackage> getPackages() {
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
List<ReactPackage> packages = new PackageList(this).getPackages();
|
||||
// Packages that cannot be autolinked yet can be added manually here, for example:
|
||||
packages.add(new com.spacedrive.app.SpacedrivePackage());
|
||||
return packages;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getJSMainModuleName() {
|
||||
return "index";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isNewArchEnabled() {
|
||||
return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean isHermesEnabled() {
|
||||
return BuildConfig.IS_HERMES_ENABLED;
|
||||
}
|
||||
});
|
||||
|
||||
private final ReactNativeHost mNewArchitectureNativeHost =
|
||||
new ReactNativeHostWrapper(this, new MainApplicationReactNativeHost(this));
|
||||
|
||||
@Override
|
||||
public ReactNativeHost getReactNativeHost() {
|
||||
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
||||
return mNewArchitectureNativeHost;
|
||||
} else {
|
||||
return mReactNativeHost;
|
||||
}
|
||||
return mReactNativeHost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
// If you opted-in for the New Architecture, we enable the TurboModule system
|
||||
ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
|
||||
SoLoader.init(this, /* native exopackage */ false);
|
||||
|
||||
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
|
||||
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
||||
// If you opted-in for the New Architecture, we load the native entry point for this app.
|
||||
DefaultNewArchitectureEntryPoint.load();
|
||||
}
|
||||
ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
|
||||
ApplicationLifecycleDispatcher.onApplicationCreate(this);
|
||||
}
|
||||
|
||||
|
@ -72,35 +73,4 @@ public class MainApplication extends Application implements ReactApplication {
|
|||
super.onConfigurationChanged(newConfig);
|
||||
ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads Flipper in React Native templates. Call this in the onCreate method with something like
|
||||
* initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
|
||||
*
|
||||
* @param context
|
||||
* @param reactInstanceManager
|
||||
*/
|
||||
private static void initializeFlipper(
|
||||
Context context, ReactInstanceManager reactInstanceManager) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
try {
|
||||
/*
|
||||
We use reflection here to pick up the class that initializes Flipper,
|
||||
since Flipper library is not available in release mode
|
||||
*/
|
||||
Class<?> aClass = Class.forName("com.spacedrive.app.ReactNativeFlipper");
|
||||
aClass
|
||||
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
|
||||
.invoke(null, context, reactInstanceManager);
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
package com.spacedrive.app.newarchitecture;
|
||||
|
||||
import android.app.Application;
|
||||
import androidx.annotation.NonNull;
|
||||
import com.facebook.react.PackageList;
|
||||
import com.facebook.react.ReactInstanceManager;
|
||||
import com.facebook.react.ReactNativeHost;
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
|
||||
import com.facebook.react.bridge.JSIModulePackage;
|
||||
import com.facebook.react.bridge.JSIModuleProvider;
|
||||
import com.facebook.react.bridge.JSIModuleSpec;
|
||||
import com.facebook.react.bridge.JSIModuleType;
|
||||
import com.facebook.react.bridge.JavaScriptContextHolder;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.UIManager;
|
||||
import com.facebook.react.fabric.ComponentFactory;
|
||||
import com.facebook.react.fabric.CoreComponentsRegistry;
|
||||
import com.facebook.react.fabric.EmptyReactNativeConfig;
|
||||
import com.facebook.react.fabric.FabricJSIModuleProvider;
|
||||
import com.facebook.react.fabric.ReactNativeConfig;
|
||||
import com.facebook.react.uimanager.ViewManagerRegistry;
|
||||
import com.spacedrive.app.BuildConfig;
|
||||
import com.spacedrive.app.newarchitecture.components.MainComponentsRegistry;
|
||||
import com.spacedrive.app.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A {@link ReactNativeHost} that helps you load everything needed for the New Architecture, both
|
||||
* TurboModule delegates and the Fabric Renderer.
|
||||
*
|
||||
* <p>Please note that this class is used ONLY if you opt-in for the New Architecture (see the
|
||||
* `newArchEnabled` property). Is ignored otherwise.
|
||||
*/
|
||||
public class MainApplicationReactNativeHost extends ReactNativeHost {
|
||||
public MainApplicationReactNativeHost(Application application) {
|
||||
super(application);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getUseDeveloperSupport() {
|
||||
return BuildConfig.DEBUG;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ReactPackage> getPackages() {
|
||||
List<ReactPackage> packages = new PackageList(this).getPackages();
|
||||
// Packages that cannot be autolinked yet can be added manually here, for example:
|
||||
// packages.add(new MyReactNativePackage());
|
||||
// TurboModules must also be loaded here providing a valid TurboReactPackage implementation:
|
||||
// packages.add(new TurboReactPackage() { ... });
|
||||
// If you have custom Fabric Components, their ViewManagers should also be loaded here
|
||||
// inside a ReactPackage.
|
||||
return packages;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getJSMainModuleName() {
|
||||
return "index";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected ReactPackageTurboModuleManagerDelegate.Builder
|
||||
getReactPackageTurboModuleManagerDelegateBuilder() {
|
||||
// Here we provide the ReactPackageTurboModuleManagerDelegate Builder. This is necessary
|
||||
// for the new architecture and to use TurboModules correctly.
|
||||
return new MainApplicationTurboModuleManagerDelegate.Builder();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JSIModulePackage getJSIModulePackage() {
|
||||
return new JSIModulePackage() {
|
||||
@Override
|
||||
public List<JSIModuleSpec> getJSIModules(
|
||||
final ReactApplicationContext reactApplicationContext,
|
||||
final JavaScriptContextHolder jsContext) {
|
||||
final List<JSIModuleSpec> specs = new ArrayList<>();
|
||||
|
||||
// Here we provide a new JSIModuleSpec that will be responsible of providing the
|
||||
// custom Fabric Components.
|
||||
specs.add(
|
||||
new JSIModuleSpec() {
|
||||
@Override
|
||||
public JSIModuleType getJSIModuleType() {
|
||||
return JSIModuleType.UIManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSIModuleProvider<UIManager> getJSIModuleProvider() {
|
||||
final ComponentFactory componentFactory = new ComponentFactory();
|
||||
CoreComponentsRegistry.register(componentFactory);
|
||||
|
||||
// Here we register a Components Registry.
|
||||
// The one that is generated with the template contains no components
|
||||
// and just provides you the one from React Native core.
|
||||
MainComponentsRegistry.register(componentFactory);
|
||||
|
||||
final ReactInstanceManager reactInstanceManager = getReactInstanceManager();
|
||||
|
||||
ViewManagerRegistry viewManagerRegistry =
|
||||
new ViewManagerRegistry(
|
||||
reactInstanceManager.getOrCreateViewManagers(reactApplicationContext));
|
||||
|
||||
return new FabricJSIModuleProvider(
|
||||
reactApplicationContext,
|
||||
componentFactory,
|
||||
ReactNativeConfig.DEFAULT_CONFIG,
|
||||
viewManagerRegistry);
|
||||
}
|
||||
});
|
||||
return specs;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package com.spacedrive.app.newarchitecture.components;
|
||||
|
||||
import com.facebook.jni.HybridData;
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
import com.facebook.react.fabric.ComponentFactory;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
|
||||
/**
|
||||
* Class responsible to load the custom Fabric Components. This class has native methods and needs a
|
||||
* corresponding C++ implementation/header file to work correctly (already placed inside the jni/
|
||||
* folder for you).
|
||||
*
|
||||
* <p>Please note that this class is used ONLY if you opt-in for the New Architecture (see the
|
||||
* `newArchEnabled` property). Is ignored otherwise.
|
||||
*/
|
||||
@DoNotStrip
|
||||
public class MainComponentsRegistry {
|
||||
static {
|
||||
SoLoader.loadLibrary("fabricjni");
|
||||
}
|
||||
|
||||
@DoNotStrip private final HybridData mHybridData;
|
||||
|
||||
@DoNotStrip
|
||||
private native HybridData initHybrid(ComponentFactory componentFactory);
|
||||
|
||||
@DoNotStrip
|
||||
private MainComponentsRegistry(ComponentFactory componentFactory) {
|
||||
mHybridData = initHybrid(componentFactory);
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
public static MainComponentsRegistry register(ComponentFactory componentFactory) {
|
||||
return new MainComponentsRegistry(componentFactory);
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
package com.spacedrive.app.newarchitecture.modules;
|
||||
|
||||
import com.facebook.jni.HybridData;
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Class responsible to load the TurboModules. This class has native methods and needs a
|
||||
* corresponding C++ implementation/header file to work correctly (already placed inside the jni/
|
||||
* folder for you).
|
||||
*
|
||||
* <p>Please note that this class is used ONLY if you opt-in for the New Architecture (see the
|
||||
* `newArchEnabled` property). Is ignored otherwise.
|
||||
*/
|
||||
public class MainApplicationTurboModuleManagerDelegate
|
||||
extends ReactPackageTurboModuleManagerDelegate {
|
||||
|
||||
private static volatile boolean sIsSoLibraryLoaded;
|
||||
|
||||
protected MainApplicationTurboModuleManagerDelegate(
|
||||
ReactApplicationContext reactApplicationContext, List<ReactPackage> packages) {
|
||||
super(reactApplicationContext, packages);
|
||||
}
|
||||
|
||||
protected native HybridData initHybrid();
|
||||
|
||||
native boolean canCreateTurboModule(String moduleName);
|
||||
|
||||
public static class Builder extends ReactPackageTurboModuleManagerDelegate.Builder {
|
||||
protected MainApplicationTurboModuleManagerDelegate build(
|
||||
ReactApplicationContext context, List<ReactPackage> packages) {
|
||||
return new MainApplicationTurboModuleManagerDelegate(context, packages);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void maybeLoadOtherSoLibraries() {
|
||||
if (!sIsSoLibraryLoaded) {
|
||||
// If you change the name of your application .so file in the Android.mk file,
|
||||
// make sure you update the name here as well.
|
||||
SoLoader.loadLibrary("spacedrive_appmodules");
|
||||
sIsSoLibraryLoaded = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
#include "MainApplicationModuleProvider.h"
|
||||
|
||||
#include <rncore.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
std::shared_ptr<TurboModule> MainApplicationModuleProvider(
|
||||
const std::string moduleName,
|
||||
const JavaTurboModule::InitParams ¶ms) {
|
||||
// Here you can provide your own module provider for TurboModules coming from
|
||||
// either your application or from external libraries. The approach to follow
|
||||
// is similar to the following (for a library called `samplelibrary`:
|
||||
//
|
||||
// auto module = samplelibrary_ModuleProvider(moduleName, params);
|
||||
// if (module != nullptr) {
|
||||
// return module;
|
||||
// }
|
||||
// return rncore_ModuleProvider(moduleName, params);
|
||||
return rncore_ModuleProvider(moduleName, params);
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -1,16 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <ReactCommon/JavaTurboModule.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
std::shared_ptr<TurboModule> MainApplicationModuleProvider(
|
||||
const std::string moduleName,
|
||||
const JavaTurboModule::InitParams ¶ms);
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -1,45 +0,0 @@
|
|||
#include "MainApplicationTurboModuleManagerDelegate.h"
|
||||
#include "MainApplicationModuleProvider.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
jni::local_ref<MainApplicationTurboModuleManagerDelegate::jhybriddata>
|
||||
MainApplicationTurboModuleManagerDelegate::initHybrid(
|
||||
jni::alias_ref<jhybridobject>) {
|
||||
return makeCxxInstance();
|
||||
}
|
||||
|
||||
void MainApplicationTurboModuleManagerDelegate::registerNatives() {
|
||||
registerHybrid({
|
||||
makeNativeMethod(
|
||||
"initHybrid", MainApplicationTurboModuleManagerDelegate::initHybrid),
|
||||
makeNativeMethod(
|
||||
"canCreateTurboModule",
|
||||
MainApplicationTurboModuleManagerDelegate::canCreateTurboModule),
|
||||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<TurboModule>
|
||||
MainApplicationTurboModuleManagerDelegate::getTurboModule(
|
||||
const std::string name,
|
||||
const std::shared_ptr<CallInvoker> jsInvoker) {
|
||||
// Not implemented yet: provide pure-C++ NativeModules here.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<TurboModule>
|
||||
MainApplicationTurboModuleManagerDelegate::getTurboModule(
|
||||
const std::string name,
|
||||
const JavaTurboModule::InitParams ¶ms) {
|
||||
return MainApplicationModuleProvider(name, params);
|
||||
}
|
||||
|
||||
bool MainApplicationTurboModuleManagerDelegate::canCreateTurboModule(
|
||||
std::string name) {
|
||||
return getTurboModule(name, nullptr) != nullptr ||
|
||||
getTurboModule(name, {.moduleName = name}) != nullptr;
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -1,38 +0,0 @@
|
|||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <ReactCommon/TurboModuleManagerDelegate.h>
|
||||
#include <fbjni/fbjni.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
class MainApplicationTurboModuleManagerDelegate
|
||||
: public jni::HybridClass<
|
||||
MainApplicationTurboModuleManagerDelegate,
|
||||
TurboModuleManagerDelegate> {
|
||||
public:
|
||||
// Adapt it to the package you used for your Java class.
|
||||
static constexpr auto kJavaDescriptor =
|
||||
"Lcom/spacedrive/app/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;";
|
||||
|
||||
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jhybridobject>);
|
||||
|
||||
static void registerNatives();
|
||||
|
||||
std::shared_ptr<TurboModule> getTurboModule(
|
||||
const std::string name,
|
||||
const std::shared_ptr<CallInvoker> jsInvoker) override;
|
||||
std::shared_ptr<TurboModule> getTurboModule(
|
||||
const std::string name,
|
||||
const JavaTurboModule::InitParams ¶ms) override;
|
||||
|
||||
/**
|
||||
* Test-only method. Allows user to verify whether a TurboModule can be
|
||||
* created by instances of this class.
|
||||
*/
|
||||
bool canCreateTurboModule(std::string name);
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -1,61 +0,0 @@
|
|||
#include "MainComponentsRegistry.h"
|
||||
|
||||
#include <CoreComponentsRegistry.h>
|
||||
#include <fbjni/fbjni.h>
|
||||
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
|
||||
#include <react/renderer/components/rncore/ComponentDescriptors.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
MainComponentsRegistry::MainComponentsRegistry(ComponentFactory *delegate) {}
|
||||
|
||||
std::shared_ptr<ComponentDescriptorProviderRegistry const>
|
||||
MainComponentsRegistry::sharedProviderRegistry() {
|
||||
auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry();
|
||||
|
||||
// Custom Fabric Components go here. You can register custom
|
||||
// components coming from your App or from 3rd party libraries here.
|
||||
//
|
||||
// providerRegistry->add(concreteComponentDescriptorProvider<
|
||||
// AocViewerComponentDescriptor>());
|
||||
return providerRegistry;
|
||||
}
|
||||
|
||||
jni::local_ref<MainComponentsRegistry::jhybriddata>
|
||||
MainComponentsRegistry::initHybrid(
|
||||
jni::alias_ref<jclass>,
|
||||
ComponentFactory *delegate) {
|
||||
auto instance = makeCxxInstance(delegate);
|
||||
|
||||
auto buildRegistryFunction =
|
||||
[](EventDispatcher::Weak const &eventDispatcher,
|
||||
ContextContainer::Shared const &contextContainer)
|
||||
-> ComponentDescriptorRegistry::Shared {
|
||||
auto registry = MainComponentsRegistry::sharedProviderRegistry()
|
||||
->createComponentDescriptorRegistry(
|
||||
{eventDispatcher, contextContainer});
|
||||
|
||||
auto mutableRegistry =
|
||||
std::const_pointer_cast<ComponentDescriptorRegistry>(registry);
|
||||
|
||||
mutableRegistry->setFallbackComponentDescriptor(
|
||||
std::make_shared<UnimplementedNativeViewComponentDescriptor>(
|
||||
ComponentDescriptorParameters{
|
||||
eventDispatcher, contextContainer, nullptr}));
|
||||
|
||||
return registry;
|
||||
};
|
||||
|
||||
delegate->buildRegistryFunction = buildRegistryFunction;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void MainComponentsRegistry::registerNatives() {
|
||||
registerHybrid({
|
||||
makeNativeMethod("initHybrid", MainComponentsRegistry::initHybrid),
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -1,32 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <ComponentFactory.h>
|
||||
#include <fbjni/fbjni.h>
|
||||
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
|
||||
#include <react/renderer/componentregistry/ComponentDescriptorRegistry.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
class MainComponentsRegistry
|
||||
: public facebook::jni::HybridClass<MainComponentsRegistry> {
|
||||
public:
|
||||
// Adapt it to the package you used for your Java class.
|
||||
constexpr static auto kJavaDescriptor =
|
||||
"Lcom/spacedrive/app/newarchitecture/components/MainComponentsRegistry;";
|
||||
|
||||
static void registerNatives();
|
||||
|
||||
MainComponentsRegistry(ComponentFactory *delegate);
|
||||
|
||||
private:
|
||||
static std::shared_ptr<ComponentDescriptorProviderRegistry const>
|
||||
sharedProviderRegistry();
|
||||
|
||||
static jni::local_ref<jhybriddata> initHybrid(
|
||||
jni::alias_ref<jclass>,
|
||||
ComponentFactory *delegate);
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -1,11 +0,0 @@
|
|||
#include <fbjni/fbjni.h>
|
||||
#include "MainApplicationTurboModuleManagerDelegate.h"
|
||||
#include "MainComponentsRegistry.h"
|
||||
|
||||
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
|
||||
return facebook::jni::initialize(vm, [] {
|
||||
facebook::react::MainApplicationTurboModuleManagerDelegate::
|
||||
registerNatives();
|
||||
facebook::react::MainComponentsRegistry::registerNatives();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
|
||||
* directory of this source tree.
|
||||
*/
|
||||
package com.spacedrive.app;
|
||||
|
||||
import android.content.Context;
|
||||
import com.facebook.react.ReactInstanceManager;
|
||||
|
||||
/**
|
||||
* Class responsible of loading Flipper inside your React Native application. This is the release
|
||||
* flavor of it so it's empty as we don't want to load Flipper.
|
||||
*/
|
||||
public class ReactNativeFlipper {
|
||||
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
|
||||
// Do nothing as we don't want to initialize Flipper on Release.
|
||||
}
|
||||
}
|
|
@ -4,38 +4,31 @@ import org.apache.tools.ant.taskdefs.condition.Os
|
|||
|
||||
buildscript {
|
||||
ext {
|
||||
buildToolsVersion = findProperty('android.buildToolsVersion') ?: '31.0.0'
|
||||
buildToolsVersion = findProperty('android.buildToolsVersion') ?: '33.0.0'
|
||||
minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '21')
|
||||
compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '31')
|
||||
targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '31')
|
||||
reactNativeVersion = "0.69.4" // https://github.com/expo/expo/issues/18129
|
||||
compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '33')
|
||||
targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '33')
|
||||
if (findProperty('android.kotlinVersion')) {
|
||||
kotlinVersion = findProperty('android.kotlinVersion')
|
||||
}
|
||||
frescoVersion = findProperty('expo.frescoVersion') ?: '2.5.0'
|
||||
|
||||
if (System.properties['os.arch'] == 'aarch64') {
|
||||
// For M1 Users we need to use the NDK 24 which added support for aarch64
|
||||
ndkVersion = '24.0.8215888'
|
||||
} else {
|
||||
// Otherwise we default to the side-by-side NDK version from AGP.
|
||||
ndkVersion = '21.4.7075529'
|
||||
}
|
||||
// We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP.
|
||||
ndkVersion = "23.1.7779620"
|
||||
}
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
// Spacedrive -- Required for the Android Rust plugin.
|
||||
maven {
|
||||
url "https://plugins.gradle.org/m2/"
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath('com.android.tools.build:gradle:7.1.1')
|
||||
classpath('com.android.tools.build:gradle:7.4.1')
|
||||
classpath('com.facebook.react:react-native-gradle-plugin')
|
||||
classpath('de.undercouch:gradle-download-task:5.0.1')
|
||||
// Spacedrive -- Rust plugin.
|
||||
classpath('org.mozilla.rust-android-gradle:plugin:0.9.3')
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,13 +45,7 @@ allprojects {
|
|||
}
|
||||
|
||||
google()
|
||||
mavenCentral {
|
||||
// We don't want to fetch react-native from Maven Central as there are
|
||||
// older versions over there.
|
||||
content {
|
||||
excludeGroup 'com.facebook.react'
|
||||
}
|
||||
}
|
||||
mavenCentral()
|
||||
maven { url 'https://www.jitpack.io' }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,4 +50,4 @@ expo.gif.enabled=true
|
|||
expo.webp.enabled=true
|
||||
# Enable animated webp support (~3.4 MB increase)
|
||||
# Disabled by default because iOS doesn't support animated webp
|
||||
expo.webp.animated=false
|
||||
expo.webp.animated=false
|
|
@ -1,5 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
8
apps/mobile/android/gradlew
vendored
8
apps/mobile/android/gradlew
vendored
|
@ -205,6 +205,12 @@ set -- \
|
|||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
|
@ -231,4 +237,4 @@ eval "set -- $(
|
|||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
exec "$JAVACMD" "$@"
|
16
apps/mobile/android/gradlew.bat
vendored
16
apps/mobile/android/gradlew.bat
vendored
|
@ -14,7 +14,7 @@
|
|||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
|
@ -25,7 +25,7 @@
|
|||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
|
@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
|||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
@ -75,15 +75,17 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
:omega
|
|
@ -7,11 +7,4 @@ apply from: new File(["node", "--print", "require.resolve('@react-native-communi
|
|||
applyNativeModulesSettingsGradle(settings)
|
||||
|
||||
include ':app'
|
||||
includeBuild(new File(["node", "--print", "require.resolve('react-native-gradle-plugin/package.json')"].execute(null, rootDir).text.trim()).getParentFile())
|
||||
|
||||
if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") {
|
||||
include(":ReactAndroid")
|
||||
project(":ReactAndroid").projectDir = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), "../ReactAndroid");
|
||||
include(":ReactAndroid:hermes-engine")
|
||||
project(":ReactAndroid:hermes-engine").projectDir = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), "../ReactAndroid/hermes-engine");
|
||||
}
|
||||
includeBuild(new File(["node", "--print", "require.resolve('react-native-gradle-plugin/package.json')"].execute(null, rootDir).text.trim()).getParentFile())
|
|
@ -7,6 +7,7 @@
|
|||
"orientation": "portrait",
|
||||
"jsEngine": "hermes",
|
||||
"scheme": "spacedrive",
|
||||
"platforms": ["ios", "android"],
|
||||
"userInterfaceStyle": "automatic",
|
||||
"updates": {
|
||||
"enabled": false,
|
||||
|
|
|
@ -5,34 +5,62 @@ require File.join(File.dirname(`node --print "require.resolve('@react-native-com
|
|||
require 'json'
|
||||
podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {}
|
||||
|
||||
ENV['RCT_NEW_ARCH_ENABLED'] = podfile_properties['newArchEnabled'] == 'true' ? '1' : '0'
|
||||
|
||||
platform :ios, podfile_properties['ios.deploymentTarget'] || '13.0'
|
||||
install! 'cocoapods',
|
||||
:deterministic_uuids => false
|
||||
|
||||
prepare_react_native_project!
|
||||
|
||||
# If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set.
|
||||
# because `react-native-flipper` depends on (FlipperKit,...), which will be excluded. To fix this,
|
||||
# you can also exclude `react-native-flipper` in `react-native.config.js`
|
||||
#
|
||||
# ```js
|
||||
# module.exports = {
|
||||
# dependencies: {
|
||||
# ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}),
|
||||
# }
|
||||
# }
|
||||
# ```
|
||||
flipper_config = FlipperConfiguration.disabled
|
||||
if ENV['NO_FLIPPER'] == '1' then
|
||||
# Explicitly disabled through environment variables
|
||||
flipper_config = FlipperConfiguration.disabled
|
||||
elsif podfile_properties.key?('ios.flipper') then
|
||||
# Configure Flipper in Podfile.properties.json
|
||||
if podfile_properties['ios.flipper'] == 'true' then
|
||||
flipper_config = FlipperConfiguration.enabled(["Debug", "Release"])
|
||||
elsif podfile_properties['ios.flipper'] != 'false' then
|
||||
flipper_config = FlipperConfiguration.enabled(["Debug", "Release"], { 'Flipper' => podfile_properties['ios.flipper'] })
|
||||
end
|
||||
end
|
||||
|
||||
target 'Spacedrive' do
|
||||
use_expo_modules!
|
||||
config = use_native_modules!
|
||||
|
||||
use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']
|
||||
use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS']
|
||||
|
||||
# Flags change depending on the env values.
|
||||
flags = get_default_flags()
|
||||
|
||||
use_react_native!(
|
||||
:path => config[:reactNativePath],
|
||||
:hermes_enabled => podfile_properties['expo.jsEngine'] == 'hermes',
|
||||
:hermes_enabled => podfile_properties['expo.jsEngine'] == nil || podfile_properties['expo.jsEngine'] == 'hermes',
|
||||
:fabric_enabled => flags[:fabric_enabled],
|
||||
# An absolute path to your application root.
|
||||
:app_path => "#{Pod::Config.instance.installation_root}/..",
|
||||
#
|
||||
# Uncomment to opt-in to using Flipper
|
||||
# Note that if you have use_frameworks! enabled, Flipper will not work
|
||||
# :flipper_configuration => !ENV['CI'] ? FlipperConfiguration.enabled : FlipperConfiguration.disabled,
|
||||
# Note that if you have use_frameworks! enabled, Flipper will not work if enabled
|
||||
:flipper_configuration => flipper_config
|
||||
)
|
||||
|
||||
post_install do |installer|
|
||||
react_native_post_install(
|
||||
installer,
|
||||
config[:reactNativePath],
|
||||
# Set `mac_catalyst_enabled` to `true` in order to apply patches
|
||||
# necessary for Mac Catalyst builds
|
||||
:mac_catalyst_enabled => false
|
||||
|
|
|
@ -1,38 +1,41 @@
|
|||
PODS:
|
||||
- boost (1.76.0)
|
||||
- DoubleConversion (1.1.6)
|
||||
- EXApplication (5.0.1):
|
||||
- EXApplication (5.1.1):
|
||||
- ExpoModulesCore
|
||||
- EXConstants (14.0.2):
|
||||
- EXConstants (14.2.1):
|
||||
- ExpoModulesCore
|
||||
- EXFileSystem (15.1.1):
|
||||
- EXFileSystem (15.2.2):
|
||||
- ExpoModulesCore
|
||||
- EXFont (11.0.1):
|
||||
- EXFont (11.1.1):
|
||||
- ExpoModulesCore
|
||||
- EXMediaLibrary (15.0.0):
|
||||
- EXMediaLibrary (15.2.2):
|
||||
- ExpoModulesCore
|
||||
- React-Core
|
||||
- Expo (47.0.13):
|
||||
- Expo (48.0.6):
|
||||
- ExpoModulesCore
|
||||
- ExpoKeepAwake (11.0.1):
|
||||
- ExpoKeepAwake (12.0.1):
|
||||
- ExpoModulesCore
|
||||
- ExpoModulesCore (1.1.1):
|
||||
- ExpoModulesCore (1.2.4):
|
||||
- React-Core
|
||||
- React-RCTAppDelegate
|
||||
- ReactCommon/turbomodule/core
|
||||
- EXSplashScreen (0.17.5):
|
||||
- EXSplashScreen (0.18.1):
|
||||
- ExpoModulesCore
|
||||
- React-Core
|
||||
- FBLazyVector (0.70.5)
|
||||
- FBReactNativeSpec (0.70.5):
|
||||
- FBLazyVector (0.71.3)
|
||||
- FBReactNativeSpec (0.71.3):
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- RCTRequired (= 0.70.5)
|
||||
- RCTTypeSafety (= 0.70.5)
|
||||
- React-Core (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- ReactCommon/turbomodule/core (= 0.70.5)
|
||||
- RCTRequired (= 0.71.3)
|
||||
- RCTTypeSafety (= 0.71.3)
|
||||
- React-Core (= 0.71.3)
|
||||
- React-jsi (= 0.71.3)
|
||||
- ReactCommon/turbomodule/core (= 0.71.3)
|
||||
- fmt (6.2.1)
|
||||
- glog (0.3.5)
|
||||
- hermes-engine (0.70.5)
|
||||
- hermes-engine (0.71.3):
|
||||
- hermes-engine/Pre-built (= 0.71.3)
|
||||
- hermes-engine/Pre-built (0.71.3)
|
||||
- libevent (2.1.12)
|
||||
- lottie-ios (3.4.4)
|
||||
- lottie-react-native (5.1.4):
|
||||
|
@ -55,214 +58,239 @@ PODS:
|
|||
- fmt (~> 6.2.1)
|
||||
- glog
|
||||
- libevent
|
||||
- RCTRequired (0.70.5)
|
||||
- RCTTypeSafety (0.70.5):
|
||||
- FBLazyVector (= 0.70.5)
|
||||
- RCTRequired (= 0.70.5)
|
||||
- React-Core (= 0.70.5)
|
||||
- React (0.70.5):
|
||||
- React-Core (= 0.70.5)
|
||||
- React-Core/DevSupport (= 0.70.5)
|
||||
- React-Core/RCTWebSocket (= 0.70.5)
|
||||
- React-RCTActionSheet (= 0.70.5)
|
||||
- React-RCTAnimation (= 0.70.5)
|
||||
- React-RCTBlob (= 0.70.5)
|
||||
- React-RCTImage (= 0.70.5)
|
||||
- React-RCTLinking (= 0.70.5)
|
||||
- React-RCTNetwork (= 0.70.5)
|
||||
- React-RCTSettings (= 0.70.5)
|
||||
- React-RCTText (= 0.70.5)
|
||||
- React-RCTVibration (= 0.70.5)
|
||||
- React-bridging (0.70.5):
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-callinvoker (0.70.5)
|
||||
- React-Codegen (0.70.5):
|
||||
- FBReactNativeSpec (= 0.70.5)
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- RCTRequired (= 0.70.5)
|
||||
- RCTTypeSafety (= 0.70.5)
|
||||
- React-Core (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-jsiexecutor (= 0.70.5)
|
||||
- ReactCommon/turbomodule/core (= 0.70.5)
|
||||
- React-Core (0.70.5):
|
||||
- RCTRequired (0.71.3)
|
||||
- RCTTypeSafety (0.71.3):
|
||||
- FBLazyVector (= 0.71.3)
|
||||
- RCTRequired (= 0.71.3)
|
||||
- React-Core (= 0.71.3)
|
||||
- React (0.71.3):
|
||||
- React-Core (= 0.71.3)
|
||||
- React-Core/DevSupport (= 0.71.3)
|
||||
- React-Core/RCTWebSocket (= 0.71.3)
|
||||
- React-RCTActionSheet (= 0.71.3)
|
||||
- React-RCTAnimation (= 0.71.3)
|
||||
- React-RCTBlob (= 0.71.3)
|
||||
- React-RCTImage (= 0.71.3)
|
||||
- React-RCTLinking (= 0.71.3)
|
||||
- React-RCTNetwork (= 0.71.3)
|
||||
- React-RCTSettings (= 0.71.3)
|
||||
- React-RCTText (= 0.71.3)
|
||||
- React-RCTVibration (= 0.71.3)
|
||||
- React-callinvoker (0.71.3)
|
||||
- React-Codegen (0.71.3):
|
||||
- FBReactNativeSpec
|
||||
- hermes-engine
|
||||
- RCT-Folly
|
||||
- RCTRequired
|
||||
- RCTTypeSafety
|
||||
- React-Core
|
||||
- React-jsi
|
||||
- React-jsiexecutor
|
||||
- ReactCommon/turbomodule/bridging
|
||||
- ReactCommon/turbomodule/core
|
||||
- React-Core (0.71.3):
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default (= 0.70.5)
|
||||
- React-cxxreact (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-jsiexecutor (= 0.70.5)
|
||||
- React-perflogger (= 0.70.5)
|
||||
- React-Core/Default (= 0.71.3)
|
||||
- React-cxxreact (= 0.71.3)
|
||||
- React-hermes
|
||||
- React-jsi (= 0.71.3)
|
||||
- React-jsiexecutor (= 0.71.3)
|
||||
- React-perflogger (= 0.71.3)
|
||||
- Yoga
|
||||
- React-Core/CoreModulesHeaders (0.70.5):
|
||||
- React-Core/CoreModulesHeaders (0.71.3):
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-jsiexecutor (= 0.70.5)
|
||||
- React-perflogger (= 0.70.5)
|
||||
- React-cxxreact (= 0.71.3)
|
||||
- React-hermes
|
||||
- React-jsi (= 0.71.3)
|
||||
- React-jsiexecutor (= 0.71.3)
|
||||
- React-perflogger (= 0.71.3)
|
||||
- Yoga
|
||||
- React-Core/Default (0.70.5):
|
||||
- React-Core/Default (0.71.3):
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-cxxreact (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-jsiexecutor (= 0.70.5)
|
||||
- React-perflogger (= 0.70.5)
|
||||
- React-cxxreact (= 0.71.3)
|
||||
- React-hermes
|
||||
- React-jsi (= 0.71.3)
|
||||
- React-jsiexecutor (= 0.71.3)
|
||||
- React-perflogger (= 0.71.3)
|
||||
- Yoga
|
||||
- React-Core/DevSupport (0.70.5):
|
||||
- React-Core/DevSupport (0.71.3):
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default (= 0.70.5)
|
||||
- React-Core/RCTWebSocket (= 0.70.5)
|
||||
- React-cxxreact (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-jsiexecutor (= 0.70.5)
|
||||
- React-jsinspector (= 0.70.5)
|
||||
- React-perflogger (= 0.70.5)
|
||||
- React-Core/Default (= 0.71.3)
|
||||
- React-Core/RCTWebSocket (= 0.71.3)
|
||||
- React-cxxreact (= 0.71.3)
|
||||
- React-hermes
|
||||
- React-jsi (= 0.71.3)
|
||||
- React-jsiexecutor (= 0.71.3)
|
||||
- React-jsinspector (= 0.71.3)
|
||||
- React-perflogger (= 0.71.3)
|
||||
- Yoga
|
||||
- React-Core/RCTActionSheetHeaders (0.70.5):
|
||||
- React-Core/RCTActionSheetHeaders (0.71.3):
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-jsiexecutor (= 0.70.5)
|
||||
- React-perflogger (= 0.70.5)
|
||||
- React-cxxreact (= 0.71.3)
|
||||
- React-hermes
|
||||
- React-jsi (= 0.71.3)
|
||||
- React-jsiexecutor (= 0.71.3)
|
||||
- React-perflogger (= 0.71.3)
|
||||
- Yoga
|
||||
- React-Core/RCTAnimationHeaders (0.70.5):
|
||||
- React-Core/RCTAnimationHeaders (0.71.3):
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-jsiexecutor (= 0.70.5)
|
||||
- React-perflogger (= 0.70.5)
|
||||
- React-cxxreact (= 0.71.3)
|
||||
- React-hermes
|
||||
- React-jsi (= 0.71.3)
|
||||
- React-jsiexecutor (= 0.71.3)
|
||||
- React-perflogger (= 0.71.3)
|
||||
- Yoga
|
||||
- React-Core/RCTBlobHeaders (0.70.5):
|
||||
- React-Core/RCTBlobHeaders (0.71.3):
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-jsiexecutor (= 0.70.5)
|
||||
- React-perflogger (= 0.70.5)
|
||||
- React-cxxreact (= 0.71.3)
|
||||
- React-hermes
|
||||
- React-jsi (= 0.71.3)
|
||||
- React-jsiexecutor (= 0.71.3)
|
||||
- React-perflogger (= 0.71.3)
|
||||
- Yoga
|
||||
- React-Core/RCTImageHeaders (0.70.5):
|
||||
- React-Core/RCTImageHeaders (0.71.3):
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-jsiexecutor (= 0.70.5)
|
||||
- React-perflogger (= 0.70.5)
|
||||
- React-cxxreact (= 0.71.3)
|
||||
- React-hermes
|
||||
- React-jsi (= 0.71.3)
|
||||
- React-jsiexecutor (= 0.71.3)
|
||||
- React-perflogger (= 0.71.3)
|
||||
- Yoga
|
||||
- React-Core/RCTLinkingHeaders (0.70.5):
|
||||
- React-Core/RCTLinkingHeaders (0.71.3):
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-jsiexecutor (= 0.70.5)
|
||||
- React-perflogger (= 0.70.5)
|
||||
- React-cxxreact (= 0.71.3)
|
||||
- React-hermes
|
||||
- React-jsi (= 0.71.3)
|
||||
- React-jsiexecutor (= 0.71.3)
|
||||
- React-perflogger (= 0.71.3)
|
||||
- Yoga
|
||||
- React-Core/RCTNetworkHeaders (0.70.5):
|
||||
- React-Core/RCTNetworkHeaders (0.71.3):
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-jsiexecutor (= 0.70.5)
|
||||
- React-perflogger (= 0.70.5)
|
||||
- React-cxxreact (= 0.71.3)
|
||||
- React-hermes
|
||||
- React-jsi (= 0.71.3)
|
||||
- React-jsiexecutor (= 0.71.3)
|
||||
- React-perflogger (= 0.71.3)
|
||||
- Yoga
|
||||
- React-Core/RCTSettingsHeaders (0.70.5):
|
||||
- React-Core/RCTSettingsHeaders (0.71.3):
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-jsiexecutor (= 0.70.5)
|
||||
- React-perflogger (= 0.70.5)
|
||||
- React-cxxreact (= 0.71.3)
|
||||
- React-hermes
|
||||
- React-jsi (= 0.71.3)
|
||||
- React-jsiexecutor (= 0.71.3)
|
||||
- React-perflogger (= 0.71.3)
|
||||
- Yoga
|
||||
- React-Core/RCTTextHeaders (0.70.5):
|
||||
- React-Core/RCTTextHeaders (0.71.3):
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-jsiexecutor (= 0.70.5)
|
||||
- React-perflogger (= 0.70.5)
|
||||
- React-cxxreact (= 0.71.3)
|
||||
- React-hermes
|
||||
- React-jsi (= 0.71.3)
|
||||
- React-jsiexecutor (= 0.71.3)
|
||||
- React-perflogger (= 0.71.3)
|
||||
- Yoga
|
||||
- React-Core/RCTVibrationHeaders (0.70.5):
|
||||
- React-Core/RCTVibrationHeaders (0.71.3):
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-jsiexecutor (= 0.70.5)
|
||||
- React-perflogger (= 0.70.5)
|
||||
- React-cxxreact (= 0.71.3)
|
||||
- React-hermes
|
||||
- React-jsi (= 0.71.3)
|
||||
- React-jsiexecutor (= 0.71.3)
|
||||
- React-perflogger (= 0.71.3)
|
||||
- Yoga
|
||||
- React-Core/RCTWebSocket (0.70.5):
|
||||
- React-Core/RCTWebSocket (0.71.3):
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default (= 0.70.5)
|
||||
- React-cxxreact (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-jsiexecutor (= 0.70.5)
|
||||
- React-perflogger (= 0.70.5)
|
||||
- React-Core/Default (= 0.71.3)
|
||||
- React-cxxreact (= 0.71.3)
|
||||
- React-hermes
|
||||
- React-jsi (= 0.71.3)
|
||||
- React-jsiexecutor (= 0.71.3)
|
||||
- React-perflogger (= 0.71.3)
|
||||
- Yoga
|
||||
- React-CoreModules (0.70.5):
|
||||
- React-CoreModules (0.71.3):
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- RCTTypeSafety (= 0.70.5)
|
||||
- React-Codegen (= 0.70.5)
|
||||
- React-Core/CoreModulesHeaders (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-RCTImage (= 0.70.5)
|
||||
- ReactCommon/turbomodule/core (= 0.70.5)
|
||||
- React-cxxreact (0.70.5):
|
||||
- RCTTypeSafety (= 0.71.3)
|
||||
- React-Codegen (= 0.71.3)
|
||||
- React-Core/CoreModulesHeaders (= 0.71.3)
|
||||
- React-jsi (= 0.71.3)
|
||||
- React-RCTBlob
|
||||
- React-RCTImage (= 0.71.3)
|
||||
- ReactCommon/turbomodule/core (= 0.71.3)
|
||||
- React-cxxreact (0.71.3):
|
||||
- boost (= 1.76.0)
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-callinvoker (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-jsinspector (= 0.70.5)
|
||||
- React-logger (= 0.70.5)
|
||||
- React-perflogger (= 0.70.5)
|
||||
- React-runtimeexecutor (= 0.70.5)
|
||||
- React-hermes (0.70.5):
|
||||
- React-callinvoker (= 0.71.3)
|
||||
- React-jsi (= 0.71.3)
|
||||
- React-jsinspector (= 0.71.3)
|
||||
- React-logger (= 0.71.3)
|
||||
- React-perflogger (= 0.71.3)
|
||||
- React-runtimeexecutor (= 0.71.3)
|
||||
- React-hermes (0.71.3):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- RCT-Folly/Futures (= 2021.07.22.00)
|
||||
- React-cxxreact (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-jsiexecutor (= 0.70.5)
|
||||
- React-jsinspector (= 0.70.5)
|
||||
- React-perflogger (= 0.70.5)
|
||||
- React-jsi (0.70.5):
|
||||
- React-cxxreact (= 0.71.3)
|
||||
- React-jsi
|
||||
- React-jsiexecutor (= 0.71.3)
|
||||
- React-jsinspector (= 0.71.3)
|
||||
- React-perflogger (= 0.71.3)
|
||||
- React-jsi (0.71.3):
|
||||
- boost (= 1.76.0)
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-jsi/Default (= 0.70.5)
|
||||
- React-jsi/Default (0.70.5):
|
||||
- boost (= 1.76.0)
|
||||
- React-jsiexecutor (0.71.3):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-jsiexecutor (0.70.5):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-cxxreact (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-perflogger (= 0.70.5)
|
||||
- React-jsinspector (0.70.5)
|
||||
- React-logger (0.70.5):
|
||||
- React-cxxreact (= 0.71.3)
|
||||
- React-jsi (= 0.71.3)
|
||||
- React-perflogger (= 0.71.3)
|
||||
- React-jsinspector (0.71.3)
|
||||
- React-logger (0.71.3):
|
||||
- glog
|
||||
- react-native-document-picker (8.1.3):
|
||||
- React-Core
|
||||
|
@ -272,77 +300,95 @@ PODS:
|
|||
- RCTTypeSafety
|
||||
- React-Core
|
||||
- ReactCommon/turbomodule/core
|
||||
- React-perflogger (0.70.5)
|
||||
- React-RCTActionSheet (0.70.5):
|
||||
- React-Core/RCTActionSheetHeaders (= 0.70.5)
|
||||
- React-RCTAnimation (0.70.5):
|
||||
- React-perflogger (0.71.3)
|
||||
- React-RCTActionSheet (0.71.3):
|
||||
- React-Core/RCTActionSheetHeaders (= 0.71.3)
|
||||
- React-RCTAnimation (0.71.3):
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- RCTTypeSafety (= 0.70.5)
|
||||
- React-Codegen (= 0.70.5)
|
||||
- React-Core/RCTAnimationHeaders (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- ReactCommon/turbomodule/core (= 0.70.5)
|
||||
- React-RCTBlob (0.70.5):
|
||||
- RCTTypeSafety (= 0.71.3)
|
||||
- React-Codegen (= 0.71.3)
|
||||
- React-Core/RCTAnimationHeaders (= 0.71.3)
|
||||
- React-jsi (= 0.71.3)
|
||||
- ReactCommon/turbomodule/core (= 0.71.3)
|
||||
- React-RCTAppDelegate (0.71.3):
|
||||
- RCT-Folly
|
||||
- RCTRequired
|
||||
- RCTTypeSafety
|
||||
- React-Core
|
||||
- ReactCommon/turbomodule/core
|
||||
- React-RCTBlob (0.71.3):
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Codegen (= 0.70.5)
|
||||
- React-Core/RCTBlobHeaders (= 0.70.5)
|
||||
- React-Core/RCTWebSocket (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-RCTNetwork (= 0.70.5)
|
||||
- ReactCommon/turbomodule/core (= 0.70.5)
|
||||
- React-RCTImage (0.70.5):
|
||||
- React-Codegen (= 0.71.3)
|
||||
- React-Core/RCTBlobHeaders (= 0.71.3)
|
||||
- React-Core/RCTWebSocket (= 0.71.3)
|
||||
- React-jsi (= 0.71.3)
|
||||
- React-RCTNetwork (= 0.71.3)
|
||||
- ReactCommon/turbomodule/core (= 0.71.3)
|
||||
- React-RCTImage (0.71.3):
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- RCTTypeSafety (= 0.70.5)
|
||||
- React-Codegen (= 0.70.5)
|
||||
- React-Core/RCTImageHeaders (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-RCTNetwork (= 0.70.5)
|
||||
- ReactCommon/turbomodule/core (= 0.70.5)
|
||||
- React-RCTLinking (0.70.5):
|
||||
- React-Codegen (= 0.70.5)
|
||||
- React-Core/RCTLinkingHeaders (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- ReactCommon/turbomodule/core (= 0.70.5)
|
||||
- React-RCTNetwork (0.70.5):
|
||||
- RCTTypeSafety (= 0.71.3)
|
||||
- React-Codegen (= 0.71.3)
|
||||
- React-Core/RCTImageHeaders (= 0.71.3)
|
||||
- React-jsi (= 0.71.3)
|
||||
- React-RCTNetwork (= 0.71.3)
|
||||
- ReactCommon/turbomodule/core (= 0.71.3)
|
||||
- React-RCTLinking (0.71.3):
|
||||
- React-Codegen (= 0.71.3)
|
||||
- React-Core/RCTLinkingHeaders (= 0.71.3)
|
||||
- React-jsi (= 0.71.3)
|
||||
- ReactCommon/turbomodule/core (= 0.71.3)
|
||||
- React-RCTNetwork (0.71.3):
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- RCTTypeSafety (= 0.70.5)
|
||||
- React-Codegen (= 0.70.5)
|
||||
- React-Core/RCTNetworkHeaders (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- ReactCommon/turbomodule/core (= 0.70.5)
|
||||
- React-RCTSettings (0.70.5):
|
||||
- RCTTypeSafety (= 0.71.3)
|
||||
- React-Codegen (= 0.71.3)
|
||||
- React-Core/RCTNetworkHeaders (= 0.71.3)
|
||||
- React-jsi (= 0.71.3)
|
||||
- ReactCommon/turbomodule/core (= 0.71.3)
|
||||
- React-RCTSettings (0.71.3):
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- RCTTypeSafety (= 0.70.5)
|
||||
- React-Codegen (= 0.70.5)
|
||||
- React-Core/RCTSettingsHeaders (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- ReactCommon/turbomodule/core (= 0.70.5)
|
||||
- React-RCTText (0.70.5):
|
||||
- React-Core/RCTTextHeaders (= 0.70.5)
|
||||
- React-RCTVibration (0.70.5):
|
||||
- RCTTypeSafety (= 0.71.3)
|
||||
- React-Codegen (= 0.71.3)
|
||||
- React-Core/RCTSettingsHeaders (= 0.71.3)
|
||||
- React-jsi (= 0.71.3)
|
||||
- ReactCommon/turbomodule/core (= 0.71.3)
|
||||
- React-RCTText (0.71.3):
|
||||
- React-Core/RCTTextHeaders (= 0.71.3)
|
||||
- React-RCTVibration (0.71.3):
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Codegen (= 0.70.5)
|
||||
- React-Core/RCTVibrationHeaders (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- ReactCommon/turbomodule/core (= 0.70.5)
|
||||
- React-runtimeexecutor (0.70.5):
|
||||
- React-jsi (= 0.70.5)
|
||||
- ReactCommon/turbomodule/core (0.70.5):
|
||||
- React-Codegen (= 0.71.3)
|
||||
- React-Core/RCTVibrationHeaders (= 0.71.3)
|
||||
- React-jsi (= 0.71.3)
|
||||
- ReactCommon/turbomodule/core (= 0.71.3)
|
||||
- React-runtimeexecutor (0.71.3):
|
||||
- React-jsi (= 0.71.3)
|
||||
- ReactCommon/turbomodule/bridging (0.71.3):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-bridging (= 0.70.5)
|
||||
- React-callinvoker (= 0.70.5)
|
||||
- React-Core (= 0.70.5)
|
||||
- React-cxxreact (= 0.70.5)
|
||||
- React-jsi (= 0.70.5)
|
||||
- React-logger (= 0.70.5)
|
||||
- React-perflogger (= 0.70.5)
|
||||
- React-callinvoker (= 0.71.3)
|
||||
- React-Core (= 0.71.3)
|
||||
- React-cxxreact (= 0.71.3)
|
||||
- React-jsi (= 0.71.3)
|
||||
- React-logger (= 0.71.3)
|
||||
- React-perflogger (= 0.71.3)
|
||||
- ReactCommon/turbomodule/core (0.71.3):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-callinvoker (= 0.71.3)
|
||||
- React-Core (= 0.71.3)
|
||||
- React-cxxreact (= 0.71.3)
|
||||
- React-jsi (= 0.71.3)
|
||||
- React-logger (= 0.71.3)
|
||||
- React-perflogger (= 0.71.3)
|
||||
- RNCAsyncStorage (1.17.11):
|
||||
- React-Core
|
||||
- RNCMaskedView (0.2.8):
|
||||
- React-Core
|
||||
- RNFlashList (1.4.1):
|
||||
- RNFlashList (1.4.0):
|
||||
- React-Core
|
||||
- RNFS (2.20.0):
|
||||
- React-Core
|
||||
|
@ -375,16 +421,16 @@ PODS:
|
|||
- React-RCTText
|
||||
- ReactCommon/turbomodule/core
|
||||
- Yoga
|
||||
- RNScreens (3.19.0):
|
||||
- RNScreens (3.20.0):
|
||||
- React-Core
|
||||
- React-RCTImage
|
||||
- RNSVG (13.8.0):
|
||||
- RNSVG (13.4.0):
|
||||
- React-Core
|
||||
- Yoga (1.14.0)
|
||||
|
||||
DEPENDENCIES:
|
||||
- boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`)
|
||||
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
|
||||
- boost (from `../../../node_modules/react-native/third-party-podspecs/boost.podspec`)
|
||||
- DoubleConversion (from `../../../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
|
||||
- EXApplication (from `../../../node_modules/expo-application/ios`)
|
||||
- EXConstants (from `../../../node_modules/expo-constants/ios`)
|
||||
- EXFileSystem (from `../../../node_modules/expo-file-system/ios`)
|
||||
|
@ -394,51 +440,51 @@ DEPENDENCIES:
|
|||
- ExpoKeepAwake (from `../../../node_modules/expo-keep-awake/ios`)
|
||||
- ExpoModulesCore (from `../../../node_modules/expo-modules-core`)
|
||||
- EXSplashScreen (from `../../../node_modules/expo-splash-screen/ios`)
|
||||
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
|
||||
- FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`)
|
||||
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
|
||||
- hermes-engine (from `../node_modules/react-native/sdks/hermes/hermes-engine.podspec`)
|
||||
- FBLazyVector (from `../../../node_modules/react-native/Libraries/FBLazyVector`)
|
||||
- FBReactNativeSpec (from `../../../node_modules/react-native/React/FBReactNativeSpec`)
|
||||
- glog (from `../../../node_modules/react-native/third-party-podspecs/glog.podspec`)
|
||||
- hermes-engine (from `../../../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`)
|
||||
- libevent (~> 2.1.12)
|
||||
- lottie-react-native (from `../node_modules/lottie-react-native`)
|
||||
- RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
|
||||
- RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
|
||||
- RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
|
||||
- React (from `../node_modules/react-native/`)
|
||||
- React-bridging (from `../node_modules/react-native/ReactCommon`)
|
||||
- React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`)
|
||||
- lottie-react-native (from `../../../node_modules/lottie-react-native`)
|
||||
- RCT-Folly (from `../../../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
|
||||
- RCTRequired (from `../../../node_modules/react-native/Libraries/RCTRequired`)
|
||||
- RCTTypeSafety (from `../../../node_modules/react-native/Libraries/TypeSafety`)
|
||||
- React (from `../../../node_modules/react-native/`)
|
||||
- React-callinvoker (from `../../../node_modules/react-native/ReactCommon/callinvoker`)
|
||||
- React-Codegen (from `build/generated/ios`)
|
||||
- React-Core (from `../node_modules/react-native/`)
|
||||
- React-Core/RCTWebSocket (from `../node_modules/react-native/`)
|
||||
- React-CoreModules (from `../node_modules/react-native/React/CoreModules`)
|
||||
- React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`)
|
||||
- React-hermes (from `../node_modules/react-native/ReactCommon/hermes`)
|
||||
- React-jsi (from `../node_modules/react-native/ReactCommon/jsi`)
|
||||
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
|
||||
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
|
||||
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
|
||||
- react-native-document-picker (from `../node_modules/react-native-document-picker`)
|
||||
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
|
||||
- React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`)
|
||||
- React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
|
||||
- React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`)
|
||||
- React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`)
|
||||
- React-RCTImage (from `../node_modules/react-native/Libraries/Image`)
|
||||
- React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`)
|
||||
- React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`)
|
||||
- React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`)
|
||||
- React-RCTText (from `../node_modules/react-native/Libraries/Text`)
|
||||
- React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
|
||||
- React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`)
|
||||
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
|
||||
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
|
||||
- "RNCMaskedView (from `../node_modules/@react-native-masked-view/masked-view`)"
|
||||
- "RNFlashList (from `../node_modules/@shopify/flash-list`)"
|
||||
- RNFS (from `../node_modules/react-native-fs`)
|
||||
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
|
||||
- RNReanimated (from `../node_modules/react-native-reanimated`)
|
||||
- RNScreens (from `../node_modules/react-native-screens`)
|
||||
- RNSVG (from `../node_modules/react-native-svg`)
|
||||
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
|
||||
- React-Core (from `../../../node_modules/react-native/`)
|
||||
- React-Core/RCTWebSocket (from `../../../node_modules/react-native/`)
|
||||
- React-CoreModules (from `../../../node_modules/react-native/React/CoreModules`)
|
||||
- React-cxxreact (from `../../../node_modules/react-native/ReactCommon/cxxreact`)
|
||||
- React-hermes (from `../../../node_modules/react-native/ReactCommon/hermes`)
|
||||
- React-jsi (from `../../../node_modules/react-native/ReactCommon/jsi`)
|
||||
- React-jsiexecutor (from `../../../node_modules/react-native/ReactCommon/jsiexecutor`)
|
||||
- React-jsinspector (from `../../../node_modules/react-native/ReactCommon/jsinspector`)
|
||||
- React-logger (from `../../../node_modules/react-native/ReactCommon/logger`)
|
||||
- react-native-document-picker (from `../../../node_modules/react-native-document-picker`)
|
||||
- react-native-safe-area-context (from `../../../node_modules/react-native-safe-area-context`)
|
||||
- React-perflogger (from `../../../node_modules/react-native/ReactCommon/reactperflogger`)
|
||||
- React-RCTActionSheet (from `../../../node_modules/react-native/Libraries/ActionSheetIOS`)
|
||||
- React-RCTAnimation (from `../../../node_modules/react-native/Libraries/NativeAnimation`)
|
||||
- React-RCTAppDelegate (from `../../../node_modules/react-native/Libraries/AppDelegate`)
|
||||
- React-RCTBlob (from `../../../node_modules/react-native/Libraries/Blob`)
|
||||
- React-RCTImage (from `../../../node_modules/react-native/Libraries/Image`)
|
||||
- React-RCTLinking (from `../../../node_modules/react-native/Libraries/LinkingIOS`)
|
||||
- React-RCTNetwork (from `../../../node_modules/react-native/Libraries/Network`)
|
||||
- React-RCTSettings (from `../../../node_modules/react-native/Libraries/Settings`)
|
||||
- React-RCTText (from `../../../node_modules/react-native/Libraries/Text`)
|
||||
- React-RCTVibration (from `../../../node_modules/react-native/Libraries/Vibration`)
|
||||
- React-runtimeexecutor (from `../../../node_modules/react-native/ReactCommon/runtimeexecutor`)
|
||||
- ReactCommon/turbomodule/core (from `../../../node_modules/react-native/ReactCommon`)
|
||||
- "RNCAsyncStorage (from `../../../node_modules/@react-native-async-storage/async-storage`)"
|
||||
- "RNCMaskedView (from `../../../node_modules/@react-native-masked-view/masked-view`)"
|
||||
- "RNFlashList (from `../../../node_modules/@shopify/flash-list`)"
|
||||
- RNFS (from `../../../node_modules/react-native-fs`)
|
||||
- RNGestureHandler (from `../../../node_modules/react-native-gesture-handler`)
|
||||
- RNReanimated (from `../../../node_modules/react-native-reanimated`)
|
||||
- RNScreens (from `../../../node_modules/react-native-screens`)
|
||||
- RNSVG (from `../../../node_modules/react-native-svg`)
|
||||
- Yoga (from `../../../node_modules/react-native/ReactCommon/yoga`)
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
|
@ -448,9 +494,9 @@ SPEC REPOS:
|
|||
|
||||
EXTERNAL SOURCES:
|
||||
boost:
|
||||
:podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec"
|
||||
:podspec: "../../../node_modules/react-native/third-party-podspecs/boost.podspec"
|
||||
DoubleConversion:
|
||||
:podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
|
||||
:podspec: "../../../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
|
||||
EXApplication:
|
||||
:path: "../../../node_modules/expo-application/ios"
|
||||
EXConstants:
|
||||
|
@ -470,151 +516,151 @@ EXTERNAL SOURCES:
|
|||
EXSplashScreen:
|
||||
:path: "../../../node_modules/expo-splash-screen/ios"
|
||||
FBLazyVector:
|
||||
:path: "../node_modules/react-native/Libraries/FBLazyVector"
|
||||
:path: "../../../node_modules/react-native/Libraries/FBLazyVector"
|
||||
FBReactNativeSpec:
|
||||
:path: "../node_modules/react-native/React/FBReactNativeSpec"
|
||||
:path: "../../../node_modules/react-native/React/FBReactNativeSpec"
|
||||
glog:
|
||||
:podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec"
|
||||
:podspec: "../../../node_modules/react-native/third-party-podspecs/glog.podspec"
|
||||
hermes-engine:
|
||||
:podspec: "../node_modules/react-native/sdks/hermes/hermes-engine.podspec"
|
||||
:podspec: "../../../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec"
|
||||
lottie-react-native:
|
||||
:path: "../node_modules/lottie-react-native"
|
||||
:path: "../../../node_modules/lottie-react-native"
|
||||
RCT-Folly:
|
||||
:podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec"
|
||||
:podspec: "../../../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec"
|
||||
RCTRequired:
|
||||
:path: "../node_modules/react-native/Libraries/RCTRequired"
|
||||
:path: "../../../node_modules/react-native/Libraries/RCTRequired"
|
||||
RCTTypeSafety:
|
||||
:path: "../node_modules/react-native/Libraries/TypeSafety"
|
||||
:path: "../../../node_modules/react-native/Libraries/TypeSafety"
|
||||
React:
|
||||
:path: "../node_modules/react-native/"
|
||||
React-bridging:
|
||||
:path: "../node_modules/react-native/ReactCommon"
|
||||
:path: "../../../node_modules/react-native/"
|
||||
React-callinvoker:
|
||||
:path: "../node_modules/react-native/ReactCommon/callinvoker"
|
||||
:path: "../../../node_modules/react-native/ReactCommon/callinvoker"
|
||||
React-Codegen:
|
||||
:path: build/generated/ios
|
||||
React-Core:
|
||||
:path: "../node_modules/react-native/"
|
||||
:path: "../../../node_modules/react-native/"
|
||||
React-CoreModules:
|
||||
:path: "../node_modules/react-native/React/CoreModules"
|
||||
:path: "../../../node_modules/react-native/React/CoreModules"
|
||||
React-cxxreact:
|
||||
:path: "../node_modules/react-native/ReactCommon/cxxreact"
|
||||
:path: "../../../node_modules/react-native/ReactCommon/cxxreact"
|
||||
React-hermes:
|
||||
:path: "../node_modules/react-native/ReactCommon/hermes"
|
||||
:path: "../../../node_modules/react-native/ReactCommon/hermes"
|
||||
React-jsi:
|
||||
:path: "../node_modules/react-native/ReactCommon/jsi"
|
||||
:path: "../../../node_modules/react-native/ReactCommon/jsi"
|
||||
React-jsiexecutor:
|
||||
:path: "../node_modules/react-native/ReactCommon/jsiexecutor"
|
||||
:path: "../../../node_modules/react-native/ReactCommon/jsiexecutor"
|
||||
React-jsinspector:
|
||||
:path: "../node_modules/react-native/ReactCommon/jsinspector"
|
||||
:path: "../../../node_modules/react-native/ReactCommon/jsinspector"
|
||||
React-logger:
|
||||
:path: "../node_modules/react-native/ReactCommon/logger"
|
||||
:path: "../../../node_modules/react-native/ReactCommon/logger"
|
||||
react-native-document-picker:
|
||||
:path: "../node_modules/react-native-document-picker"
|
||||
:path: "../../../node_modules/react-native-document-picker"
|
||||
react-native-safe-area-context:
|
||||
:path: "../node_modules/react-native-safe-area-context"
|
||||
:path: "../../../node_modules/react-native-safe-area-context"
|
||||
React-perflogger:
|
||||
:path: "../node_modules/react-native/ReactCommon/reactperflogger"
|
||||
:path: "../../../node_modules/react-native/ReactCommon/reactperflogger"
|
||||
React-RCTActionSheet:
|
||||
:path: "../node_modules/react-native/Libraries/ActionSheetIOS"
|
||||
:path: "../../../node_modules/react-native/Libraries/ActionSheetIOS"
|
||||
React-RCTAnimation:
|
||||
:path: "../node_modules/react-native/Libraries/NativeAnimation"
|
||||
:path: "../../../node_modules/react-native/Libraries/NativeAnimation"
|
||||
React-RCTAppDelegate:
|
||||
:path: "../../../node_modules/react-native/Libraries/AppDelegate"
|
||||
React-RCTBlob:
|
||||
:path: "../node_modules/react-native/Libraries/Blob"
|
||||
:path: "../../../node_modules/react-native/Libraries/Blob"
|
||||
React-RCTImage:
|
||||
:path: "../node_modules/react-native/Libraries/Image"
|
||||
:path: "../../../node_modules/react-native/Libraries/Image"
|
||||
React-RCTLinking:
|
||||
:path: "../node_modules/react-native/Libraries/LinkingIOS"
|
||||
:path: "../../../node_modules/react-native/Libraries/LinkingIOS"
|
||||
React-RCTNetwork:
|
||||
:path: "../node_modules/react-native/Libraries/Network"
|
||||
:path: "../../../node_modules/react-native/Libraries/Network"
|
||||
React-RCTSettings:
|
||||
:path: "../node_modules/react-native/Libraries/Settings"
|
||||
:path: "../../../node_modules/react-native/Libraries/Settings"
|
||||
React-RCTText:
|
||||
:path: "../node_modules/react-native/Libraries/Text"
|
||||
:path: "../../../node_modules/react-native/Libraries/Text"
|
||||
React-RCTVibration:
|
||||
:path: "../node_modules/react-native/Libraries/Vibration"
|
||||
:path: "../../../node_modules/react-native/Libraries/Vibration"
|
||||
React-runtimeexecutor:
|
||||
:path: "../node_modules/react-native/ReactCommon/runtimeexecutor"
|
||||
:path: "../../../node_modules/react-native/ReactCommon/runtimeexecutor"
|
||||
ReactCommon:
|
||||
:path: "../node_modules/react-native/ReactCommon"
|
||||
:path: "../../../node_modules/react-native/ReactCommon"
|
||||
RNCAsyncStorage:
|
||||
:path: "../node_modules/@react-native-async-storage/async-storage"
|
||||
:path: "../../../node_modules/@react-native-async-storage/async-storage"
|
||||
RNCMaskedView:
|
||||
:path: "../node_modules/@react-native-masked-view/masked-view"
|
||||
:path: "../../../node_modules/@react-native-masked-view/masked-view"
|
||||
RNFlashList:
|
||||
:path: "../node_modules/@shopify/flash-list"
|
||||
:path: "../../../node_modules/@shopify/flash-list"
|
||||
RNFS:
|
||||
:path: "../node_modules/react-native-fs"
|
||||
:path: "../../../node_modules/react-native-fs"
|
||||
RNGestureHandler:
|
||||
:path: "../node_modules/react-native-gesture-handler"
|
||||
:path: "../../../node_modules/react-native-gesture-handler"
|
||||
RNReanimated:
|
||||
:path: "../node_modules/react-native-reanimated"
|
||||
:path: "../../../node_modules/react-native-reanimated"
|
||||
RNScreens:
|
||||
:path: "../node_modules/react-native-screens"
|
||||
:path: "../../../node_modules/react-native-screens"
|
||||
RNSVG:
|
||||
:path: "../node_modules/react-native-svg"
|
||||
:path: "../../../node_modules/react-native-svg"
|
||||
Yoga:
|
||||
:path: "../node_modules/react-native/ReactCommon/yoga"
|
||||
:path: "../../../node_modules/react-native/ReactCommon/yoga"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
boost: a7c83b31436843459a1961bfd74b96033dc77234
|
||||
boost: 57d2868c099736d80fcd648bf211b4431e51a558
|
||||
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
|
||||
EXApplication: 034b1c40a8e9fe1bff76a1e511ee90dff64ad834
|
||||
EXConstants: 3c86653c422dd77e40d10cbbabb3025003977415
|
||||
EXFileSystem: 60602b6eefa6873f97172c684b7537c9760b50d6
|
||||
EXFont: 319606bfe48c33b5b5063fb0994afdc496befe80
|
||||
EXMediaLibrary: b1c4f78878e45f6a359aff3a059e1660c41b73ab
|
||||
Expo: b9fa98bf260992312ee3c424400819fb9beadafe
|
||||
ExpoKeepAwake: 69b59d0a8d2b24de9f82759c39b3821fec030318
|
||||
ExpoModulesCore: 65ae09e2b2d3dd8ece30a5acc83c569968125ab0
|
||||
EXSplashScreen: 3e989924f61a8dd07ee4ea584c6ba14be9b51949
|
||||
FBLazyVector: affa4ba1bfdaac110a789192f4d452b053a86624
|
||||
FBReactNativeSpec: fe8b5f1429cfe83a8d72dc8ed61dc7704cac8745
|
||||
EXApplication: d8f53a7eee90a870a75656280e8d4b85726ea903
|
||||
EXConstants: f348da07e21b23d2b085e270d7b74f282df1a7d9
|
||||
EXFileSystem: 844e86ca9b5375486ecc4ef06d3838d5597d895d
|
||||
EXFont: 6ea3800df746be7233208d80fe379b8ed74f4272
|
||||
EXMediaLibrary: 792fe9b828b5bfa2c5a8b629730f175af2938285
|
||||
Expo: 04ba1ddde0be07aff4306ae636a1804810679145
|
||||
ExpoKeepAwake: 69f5f627670d62318410392d03e0b5db0f85759a
|
||||
ExpoModulesCore: 1667335d4f4c9b7801990930e6f0eea42c916a21
|
||||
EXSplashScreen: cd7fb052dff5ba8311d5c2455ecbebffe1b7a8ca
|
||||
FBLazyVector: 60195509584153283780abdac5569feffb8f08cc
|
||||
FBReactNativeSpec: c5a5c4f1b95ae42a17cd22c8c89c482a7b327fe3
|
||||
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
|
||||
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
|
||||
hermes-engine: 7fe5fc6ef707b7fdcb161b63898ec500e285653d
|
||||
hermes-engine: 38bfe887e456b33b697187570a08de33969f5db7
|
||||
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
|
||||
lottie-ios: 8f97d3271e155c2d688875c29cd3c74908aef5f8
|
||||
lottie-react-native: b702fab740cdb952a8e2354713d3beda63ff97b0
|
||||
RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda
|
||||
RCTRequired: 21229f84411088e5d8538f21212de49e46cc83e2
|
||||
RCTTypeSafety: 62eed57a32924b09edaaf170a548d1fc96223086
|
||||
React: f0254ccddeeef1defe66c6b1bb9133a4f040792b
|
||||
React-bridging: e46911666b7ec19538a620a221d6396cd293d687
|
||||
React-callinvoker: 66b62e2c34546546b2f21ab0b7670346410a2b53
|
||||
React-Codegen: b6999435966df3bdf82afa3f319ba0d6f9a8532a
|
||||
React-Core: dabbc9d1fe0a11d884e6ee1599789cf8eb1058a5
|
||||
React-CoreModules: 5b6b7668f156f73a56420df9ec68ca2ec8f2e818
|
||||
React-cxxreact: c7ca2baee46db22a30fce9e639277add3c3f6ad1
|
||||
React-hermes: c93e1d759ad5560dfea54d233013d7d2c725c286
|
||||
React-jsi: a565dcb49130ed20877a9bb1105ffeecbb93d02d
|
||||
React-jsiexecutor: 31564fa6912459921568e8b0e49024285a4d584b
|
||||
React-jsinspector: badd81696361249893a80477983e697aab3c1a34
|
||||
React-logger: fdda34dd285bdb0232e059b19d9606fa0ec3bb9c
|
||||
RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1
|
||||
RCTRequired: bec48f07daf7bcdc2655a0cde84e07d24d2a9e2a
|
||||
RCTTypeSafety: 171394eebacf71e1cfad79dbfae7ee8fc16ca80a
|
||||
React: d7433ccb6a8c36e4cbed59a73c0700fc83c3e98a
|
||||
React-callinvoker: 15f165009bd22ae829b2b600e50bcc98076ce4b8
|
||||
React-Codegen: b5910000eaf1e0c2f47d29be6f82f5f1264420d7
|
||||
React-Core: b6f2f78d580a90b83fd7b0d1c6911c799f6eac82
|
||||
React-CoreModules: e0cbc1a4f4f3f60e23c476fef7ab37be363ea8c1
|
||||
React-cxxreact: c87f3f124b2117d00d410b35f16c2257e25e50fa
|
||||
React-hermes: c64ca6bdf16a7069773103c9bedaf30ec90ab38f
|
||||
React-jsi: 39729361645568e238081b3b3180fbad803f25a4
|
||||
React-jsiexecutor: 515b703d23ffadeac7687bc2d12fb08b90f0aaa1
|
||||
React-jsinspector: 9f7c9137605e72ca0343db4cea88006cb94856dd
|
||||
React-logger: 957e5dc96d9dbffc6e0f15e0ee4d2b42829ff207
|
||||
react-native-document-picker: 958e2bc82e128be69055be261aeac8d872c8d34c
|
||||
react-native-safe-area-context: 39c2d8be3328df5d437ac1700f4f3a4f75716acc
|
||||
React-perflogger: e68d3795cf5d247a0379735cbac7309adf2fb931
|
||||
React-RCTActionSheet: 05452c3b281edb27850253db13ecd4c5a65bc247
|
||||
React-RCTAnimation: 578eebac706428e68466118e84aeacf3a282b4da
|
||||
React-RCTBlob: f47a0aa61e7d1fb1a0e13da832b0da934939d71a
|
||||
React-RCTImage: 60f54b66eed65d86b6dffaf4733d09161d44929d
|
||||
React-RCTLinking: 91073205aeec4b29450ca79b709277319368ac9e
|
||||
React-RCTNetwork: ca91f2c9465a7e335c8a5fae731fd7f10572213b
|
||||
React-RCTSettings: 1a9a5d01337d55c18168c1abe0f4a589167d134a
|
||||
React-RCTText: c591e8bd9347a294d8416357ca12d779afec01d5
|
||||
React-RCTVibration: 8e5c8c5d17af641f306d7380d8d0fe9b3c142c48
|
||||
React-runtimeexecutor: 7401c4a40f8728fd89df4a56104541b760876117
|
||||
ReactCommon: c9246996e73bf75a2c6c3ff15f1e16707cdc2da9
|
||||
React-perflogger: af8a3d31546077f42d729b949925cc4549f14def
|
||||
React-RCTActionSheet: 57cc5adfefbaaf0aae2cf7e10bccd746f2903673
|
||||
React-RCTAnimation: 11c61e94da700c4dc915cf134513764d87fc5e2b
|
||||
React-RCTAppDelegate: c3980adeaadcfd6cb495532e928b36ac6db3c14a
|
||||
React-RCTBlob: ccc5049d742b41971141415ca86b83b201495695
|
||||
React-RCTImage: 7a9226b0944f1e76e8e01e35a9245c2477cdbabb
|
||||
React-RCTLinking: bbe8cc582046a9c04f79c235b73c93700263e8b4
|
||||
React-RCTNetwork: fc2ca322159dc54e06508d4f5c3e934da63dc013
|
||||
React-RCTSettings: f1e9db2cdf946426d3f2b210e4ff4ce0f0d842ef
|
||||
React-RCTText: 1c41dd57e5d742b1396b4eeb251851ce7ff0fca1
|
||||
React-RCTVibration: 5199a180d04873366a83855de55ac33ce60fe4d5
|
||||
React-runtimeexecutor: 7bf0dafc7b727d93c8cb94eb00a9d3753c446c3e
|
||||
ReactCommon: 6f65ea5b7d84deb9e386f670dd11ce499ded7b40
|
||||
RNCAsyncStorage: 8616bd5a58af409453ea4e1b246521bb76578d60
|
||||
RNCMaskedView: bc0170f389056201c82a55e242e5d90070e18e5a
|
||||
RNFlashList: 8ec7f7454721145fe84566bb9e88bcf58981c9fe
|
||||
RNFlashList: 399bf6a0db68f594ad2c86aaff3ea39564f39f8a
|
||||
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
|
||||
RNGestureHandler: 071d7a9ad81e8b83fe7663b303d132406a7d8f39
|
||||
RNReanimated: 6668b0587bebd4b15dd849b99e5a9c70fc12ed95
|
||||
RNScreens: ea4cd3a853063cda19a4e3c28d2e52180c80f4eb
|
||||
RNSVG: c1e76b81c76cdcd34b4e1188852892dc280eb902
|
||||
Yoga: eca980a5771bf114c41a754098cd85e6e0d90ed7
|
||||
RNReanimated: addc4900bf47882118d0a1b21747fa6705fa8cff
|
||||
RNScreens: 218801c16a2782546d30bd2026bb625c0302d70f
|
||||
RNSVG: 07dbd870b0dcdecc99b3a202fa37c8ca163caec2
|
||||
Yoga: 5ed1699acbba8863755998a4245daa200ff3817b
|
||||
|
||||
PODFILE CHECKSUM: 4065c8b949a453403939de6e852185dbd374d972
|
||||
PODFILE CHECKSUM: 17065850599b1e955efad7a619cf825c012744d7
|
||||
|
||||
COCOAPODS: 1.11.3
|
||||
|
|
|
@ -250,7 +250,7 @@
|
|||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Spacedrive/Pods-Spacedrive-frameworks.sh",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/hermes.framework/hermes",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
|
@ -589,7 +589,7 @@
|
|||
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\"";
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
};
|
||||
name = Debug;
|
||||
|
@ -642,7 +642,7 @@
|
|||
);
|
||||
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\"";
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import <React/RCTBridgeDelegate.h>
|
||||
#import <RCTAppDelegate.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <Expo/Expo.h>
|
||||
|
||||
@interface AppDelegate : EXAppDelegateWrapper <RCTBridgeDelegate>
|
||||
@interface AppDelegate : EXAppDelegateWrapper
|
||||
|
||||
@end
|
||||
@end
|
|
@ -1,89 +1,19 @@
|
|||
#import "AppDelegate.h"
|
||||
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTBundleURLProvider.h>
|
||||
#import <React/RCTRootView.h>
|
||||
#import <React/RCTLinkingManager.h>
|
||||
#import <React/RCTConvert.h>
|
||||
|
||||
#import <React/RCTAppSetupUtils.h>
|
||||
|
||||
#if RCT_NEW_ARCH_ENABLED
|
||||
#import <React/CoreModulesPlugins.h>
|
||||
#import <React/RCTCxxBridgeDelegate.h>
|
||||
#import <React/RCTFabricSurfaceHostingProxyRootView.h>
|
||||
#import <React/RCTSurfacePresenter.h>
|
||||
#import <React/RCTSurfacePresenterBridgeAdapter.h>
|
||||
#import <ReactCommon/RCTTurboModuleManager.h>
|
||||
|
||||
#import <react/config/ReactNativeConfig.h>
|
||||
|
||||
static NSString *const kRNConcurrentRoot = @"concurrentRoot";
|
||||
|
||||
@interface AppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate> {
|
||||
RCTTurboModuleManager *_turboModuleManager;
|
||||
RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
|
||||
std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
|
||||
facebook::react::ContextContainer::Shared _contextContainer;
|
||||
}
|
||||
@end
|
||||
#endif
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
RCTAppSetupPrepareApp(application);
|
||||
self.moduleName = @"main";
|
||||
|
||||
RCTBridge *bridge = [self.reactDelegate createBridgeWithDelegate:self launchOptions:launchOptions];
|
||||
// You can add your custom initial props in the dictionary below.
|
||||
// They will be passed down to the ViewController used by React Native.
|
||||
self.initialProps = @{};
|
||||
|
||||
#if RCT_NEW_ARCH_ENABLED
|
||||
_contextContainer = std::make_shared<facebook::react::ContextContainer const>();
|
||||
_reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();
|
||||
_contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
|
||||
_bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer];
|
||||
bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;
|
||||
#endif
|
||||
|
||||
NSDictionary *initProps = [self prepareInitialProps];
|
||||
UIView *rootView = [self.reactDelegate createRootViewWithBridge:bridge moduleName:@"main" initialProperties:initProps];
|
||||
|
||||
rootView.backgroundColor = [UIColor whiteColor];
|
||||
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||
UIViewController *rootViewController = [self.reactDelegate createRootViewController];
|
||||
rootViewController.view = rootView;
|
||||
self.window.rootViewController = rootViewController;
|
||||
[self.window makeKeyAndVisible];
|
||||
|
||||
[super application:application didFinishLaunchingWithOptions:launchOptions];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge
|
||||
{
|
||||
// If you'd like to export some custom RCTBridgeModules, add them here!
|
||||
return @[];
|
||||
}
|
||||
|
||||
/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off.
|
||||
///
|
||||
/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html
|
||||
/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture).
|
||||
/// @return: `true` if the `concurrentRoot` feture is enabled. Otherwise, it returns `false`.
|
||||
- (BOOL)concurrentRootEnabled
|
||||
{
|
||||
// Switch this bool to turn on and off the concurrent root
|
||||
return true;
|
||||
}
|
||||
|
||||
- (NSDictionary *)prepareInitialProps
|
||||
{
|
||||
NSMutableDictionary *initProps = [NSMutableDictionary new];
|
||||
#if RCT_NEW_ARCH_ENABLED
|
||||
initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]);
|
||||
#endif
|
||||
return initProps;
|
||||
return [super application:application didFinishLaunchingWithOptions:launchOptions];
|
||||
}
|
||||
|
||||
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
|
||||
|
@ -95,6 +25,16 @@ static NSString *const kRNConcurrentRoot = @"concurrentRoot";
|
|||
#endif
|
||||
}
|
||||
|
||||
/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off.
|
||||
///
|
||||
/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html
|
||||
/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture).
|
||||
/// @return: `true` if the `concurrentRoot` feature is enabled. Otherwise, it returns `false`.
|
||||
- (BOOL)concurrentRootEnabled
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Linking API
|
||||
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
|
||||
return [super application:application openURL:url options:options] || [RCTLinkingManager application:application openURL:url options:options];
|
||||
|
@ -124,43 +64,4 @@ static NSString *const kRNConcurrentRoot = @"concurrentRoot";
|
|||
return [super application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
|
||||
}
|
||||
|
||||
#if RCT_NEW_ARCH_ENABLED
|
||||
|
||||
#pragma mark - RCTCxxBridgeDelegate
|
||||
|
||||
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
|
||||
{
|
||||
_turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge
|
||||
delegate:self
|
||||
jsInvoker:bridge.jsCallInvoker];
|
||||
return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager);
|
||||
}
|
||||
|
||||
#pragma mark RCTTurboModuleManagerDelegate
|
||||
|
||||
- (Class)getModuleClassFromName:(const char *)name
|
||||
{
|
||||
return RCTCoreModulesClassProvider(name);
|
||||
}
|
||||
|
||||
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
|
||||
jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
|
||||
initParams:
|
||||
(const facebook::react::ObjCTurboModule::InitParams &)params
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
|
||||
{
|
||||
return RCTAppSetupDefaultModuleFromClass(moduleClass);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@end
|
||||
@end
|
|
@ -9,7 +9,7 @@
|
|||
<key>EXUpdatesLaunchWaitMs</key>
|
||||
<integer>0</integer>
|
||||
<key>EXUpdatesSDKVersion</key>
|
||||
<string>46.0.0</string>
|
||||
<string>48.0.0</string>
|
||||
<key>EXUpdatesURL</key>
|
||||
<string>https://exp.host/@utkudev/spacedrive</string>
|
||||
</dict>
|
||||
|
|
|
@ -6,5 +6,4 @@ int main(int argc, char * argv[]) {
|
|||
@autoreleasepool {
|
||||
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
set -e
|
||||
|
||||
export PROTOC=/opt/homebrew/bin/protoc
|
||||
|
||||
TARGET_DIRECTORY=../../../target
|
||||
|
||||
CARGO_FLAGS=
|
||||
|
|
|
@ -12,6 +12,7 @@ const projectRoot = __dirname;
|
|||
const workspaceRoot = path.resolve(projectRoot, '../..');
|
||||
|
||||
const metroConfig = makeMetroConfig({
|
||||
...expoDefaultConfig,
|
||||
projectRoot,
|
||||
watchFolders: [workspaceRoot],
|
||||
resolver: {
|
||||
|
@ -29,6 +30,7 @@ const metroConfig = makeMetroConfig({
|
|||
]
|
||||
},
|
||||
transformer: {
|
||||
...expoDefaultConfig.transformer,
|
||||
// Metro default is "uglify-es" but terser should be faster and has better defaults.
|
||||
minifierPath: 'metro-minify-terser',
|
||||
minifierConfig: {
|
||||
|
|
|
@ -11,62 +11,62 @@
|
|||
"xcode": "open ios/spacedrive.xcworkspace",
|
||||
"android-studio": "open -a '/Applications/Android Studio.app' ./android",
|
||||
"lint": "eslint src",
|
||||
"postinstall": "node scripts/postinstall.js",
|
||||
"typecheck": "tsc -b",
|
||||
"eas-build-pre-install": "npm i -g pnpm@7.18.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@gorhom/bottom-sheet": "^4.4.5",
|
||||
"@hookform/resolvers": "^2.9.11",
|
||||
"@react-native-async-storage/async-storage": "~1.17.11",
|
||||
"@react-native-masked-view/masked-view": "0.2.8",
|
||||
"@react-navigation/bottom-tabs": "^6.5.4",
|
||||
"@react-navigation/drawer": "^6.5.8",
|
||||
"@react-navigation/native": "^6.1.3",
|
||||
"@react-navigation/stack": "^6.3.12",
|
||||
"@react-navigation/bottom-tabs": "^6.5.7",
|
||||
"@react-navigation/drawer": "^6.6.2",
|
||||
"@react-navigation/native": "^6.1.6",
|
||||
"@react-navigation/stack": "^6.3.16",
|
||||
"@rspc/client": "^0.0.0-main-7c0a67c1",
|
||||
"@rspc/react": "^0.0.0-main-7c0a67c1",
|
||||
"@sd/assets": "workspace:*",
|
||||
"@sd/client": "workspace:*",
|
||||
"@shopify/flash-list": "1.4.1",
|
||||
"@tanstack/react-query": "^4.24.4",
|
||||
"@shopify/flash-list": "1.4.0",
|
||||
"@tanstack/react-query": "^4.26.1",
|
||||
"byte-size": "^8.1.0",
|
||||
"class-variance-authority": "^0.4.0",
|
||||
"dayjs": "^1.11.5",
|
||||
"expo": "^47.0.13",
|
||||
"expo-linking": "~3.3.0",
|
||||
"expo-media-library": "~15.0.0",
|
||||
"expo-splash-screen": "~0.17.5",
|
||||
"expo-status-bar": "~1.4.2",
|
||||
"expo": "^48.0.6",
|
||||
"expo-linking": "~4.0.1",
|
||||
"expo-media-library": "~15.2.2",
|
||||
"expo-splash-screen": "~0.18.1",
|
||||
"expo-status-bar": "~1.4.4",
|
||||
"intl": "^1.2.5",
|
||||
"lottie-react-native": "5.1.4",
|
||||
"moti": "^0.22.0",
|
||||
"moti": "^0.24.2",
|
||||
"phosphor-react-native": "^1.1.2",
|
||||
"react": "18.1.0",
|
||||
"react-hook-form": "^7.43.0",
|
||||
"react-native": "0.70.5",
|
||||
"react": "18.2.0",
|
||||
"react-hook-form": "^7.43.5",
|
||||
"react-native": "0.71.3",
|
||||
"react-native-document-picker": "^8.1.1",
|
||||
"react-native-fs": "^2.20.0",
|
||||
"react-native-gesture-handler": "~2.9.0",
|
||||
"react-native-popup-menu": "^0.16.1",
|
||||
"react-native-reanimated": "~2.14.4",
|
||||
"react-native-safe-area-context": "4.5.0",
|
||||
"react-native-screens": "~3.19.0",
|
||||
"react-native-svg": "13.8.0",
|
||||
"react-native-screens": "~3.20.0",
|
||||
"react-native-svg": "13.4.0",
|
||||
"react-native-wheel-color-picker": "^1.2.0",
|
||||
"twrnc": "^3.5.0",
|
||||
"twrnc": "^3.6.0",
|
||||
"use-count-up": "^3.0.1",
|
||||
"use-debounce": "^9.0.2",
|
||||
"valtio": "^1.8.0"
|
||||
"valtio": "^1.10.3",
|
||||
"zod": "^3.21.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rnx-kit/metro-config": "^1.3.5",
|
||||
"@sd/config": "workspace:*",
|
||||
"@types/react": "~18.0.26",
|
||||
"@types/react-native": "~0.70.8",
|
||||
"@types/react": "~18.0.27",
|
||||
"babel-plugin-module-resolver": "^5.0.0",
|
||||
"eslint-plugin-react-native": "^4.0.0",
|
||||
"metro-minify-terser": "^0.74.1",
|
||||
"metro-minify-terser": "0.76.0",
|
||||
"react-native-svg-transformer": "^1.0.0",
|
||||
"typescript": "^4.9.4"
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
let fs = require('fs-extra');
|
||||
let path = require('path');
|
||||
|
||||
// Not used atm, keeping it here in case we need it in the future
|
||||
async function copyReactNativeCodegen() {
|
||||
const paths = [
|
||||
['../../../node_modules/react-native-codegen', '../node_modules/react-native-codegen'],
|
||||
|
|
|
@ -1,32 +1,49 @@
|
|||
import { MotiView, useDynamicAnimation } from 'moti';
|
||||
import { PropsWithChildren, ReactNode } from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
import { StyleSheet, View, ViewProps } from 'react-native';
|
||||
import { useDerivedValue, useSharedValue } from 'react-native-reanimated';
|
||||
import Layout from '~/constants/Layout';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
|
||||
// Anything wrapped with FadeIn will fade in on mount.
|
||||
export const FadeInAnimation = ({ children, delay }: PropsWithChildren<{ delay?: number }>) => (
|
||||
<MotiView from={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ type: 'timing', delay }}>
|
||||
{children}
|
||||
</MotiView>
|
||||
);
|
||||
type MotiViewProps = PropsWithChildren<ViewProps>;
|
||||
|
||||
export const FadeInUpAnimation = ({ children, delay }: PropsWithChildren<{ delay?: number }>) => (
|
||||
// Anything wrapped with FadeIn will fade in on mount.
|
||||
export const FadeInAnimation = ({
|
||||
children,
|
||||
delay,
|
||||
...props
|
||||
}: MotiViewProps & { delay?: number }) => (
|
||||
<MotiView
|
||||
from={{ opacity: 0, translateY: 20 }}
|
||||
animate={{ opacity: 1, translateY: 0 }}
|
||||
from={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ type: 'timing', delay }}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</MotiView>
|
||||
);
|
||||
|
||||
export const LogoAnimation = ({ children }: PropsWithChildren) => (
|
||||
export const FadeInUpAnimation = ({
|
||||
children,
|
||||
delay,
|
||||
...props
|
||||
}: MotiViewProps & { delay?: number }) => (
|
||||
<MotiView
|
||||
from={{ opacity: 0, translateY: 20 }}
|
||||
animate={{ opacity: 1, translateY: 0 }}
|
||||
transition={{ type: 'timing', delay }}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</MotiView>
|
||||
);
|
||||
|
||||
export const LogoAnimation = ({ children, ...props }: MotiViewProps) => (
|
||||
<MotiView
|
||||
transition={{ type: 'timing', delay: 200 }}
|
||||
from={{ opacity: 0.8, translateY: Layout.window.width / 2 }}
|
||||
animate={{ opacity: 1, translateY: 0 }}
|
||||
transition={{ type: 'timing', delay: 200 }}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</MotiView>
|
||||
|
|
|
@ -1,19 +1,14 @@
|
|||
import AnimatedLottieView from 'lottie-react-native';
|
||||
import { StyleProp, View, ViewStyle } from 'react-native';
|
||||
import AnimatedLottieView, { AnimatedLottieViewProps } from 'lottie-react-native';
|
||||
|
||||
type Props = {
|
||||
style?: StyleProp<ViewStyle>;
|
||||
};
|
||||
type AnimationProps = Omit<AnimatedLottieViewProps, 'source'>;
|
||||
|
||||
export const PulseAnimation = ({ style }: Props) => {
|
||||
export const PulseAnimation = ({ style }: AnimationProps) => {
|
||||
return (
|
||||
<View>
|
||||
<AnimatedLottieView
|
||||
autoPlay
|
||||
loop
|
||||
source={require('@sd/assets/lottie/loading-pulse.json')}
|
||||
style={style}
|
||||
/>
|
||||
</View>
|
||||
<AnimatedLottieView
|
||||
autoPlay
|
||||
loop
|
||||
source={require('@sd/assets/lottie/loading-pulse.json')}
|
||||
style={style}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@ import { tw, twStyle } from '~/lib/tailwind';
|
|||
import { currentLibraryStore } from '~/utils/nav';
|
||||
import { AnimatedHeight } from '../animation/layout';
|
||||
import CreateLibraryDialog from '../dialog/CreateLibraryDialog';
|
||||
import Divider from '../primitive/Divider';
|
||||
import { Divider } from '../primitive/Divider';
|
||||
|
||||
const DrawerLibraryManager = () => {
|
||||
const [dropdownClosed, setDropdownClosed] = useState(true);
|
||||
|
@ -51,7 +51,7 @@ const DrawerLibraryManager = () => {
|
|||
<View style={tw`bg-sidebar-button border-sidebar-line rounded-b-md p-2`}>
|
||||
{/* Libraries */}
|
||||
{libraries.data?.map((library) => {
|
||||
console.log('library', library);
|
||||
// console.log('library', library);
|
||||
return (
|
||||
<Pressable key={library.uuid} onPress={() => (currentLibraryStore.id = library.uuid)}>
|
||||
<View
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Text, View } from 'react-native';
|
||||
import { ExplorerItem, ObjectKind, isObject } from '@sd/client';
|
||||
import { ExplorerItem } from '@sd/client';
|
||||
import Layout from '~/constants/Layout';
|
||||
import { tw, twStyle } from '~/lib/tailwind';
|
||||
import { getExplorerStore } from '~/stores/explorerStore';
|
||||
|
@ -12,10 +12,6 @@ type FileItemProps = {
|
|||
const FileItem = ({ data }: FileItemProps) => {
|
||||
const { item } = data;
|
||||
|
||||
// temp fix (will handle this on mobile-inspector branch)
|
||||
const objectData = data ? (isObject(data) ? data.item : data.item.object) : null;
|
||||
const isVid = ObjectKind[objectData?.kind || 0] === 'Video';
|
||||
|
||||
const gridItemSize = Layout.window.width / getExplorerStore().gridNumColumns;
|
||||
|
||||
return (
|
||||
|
@ -25,15 +21,7 @@ const FileItem = ({ data }: FileItemProps) => {
|
|||
height: gridItemSize
|
||||
})}
|
||||
>
|
||||
<FileThumb
|
||||
data={data}
|
||||
kind={data.item.extension === 'zip' ? 'zip' : isVid ? 'video' : 'other'}
|
||||
/>
|
||||
{item.extension && isVid && (
|
||||
<View style={tw`absolute bottom-8 right-5 rounded bg-black/70 py-0.5 px-1 opacity-70`}>
|
||||
<Text style={tw`text-[9px] font-semibold uppercase text-white`}>{item.extension}</Text>
|
||||
</View>
|
||||
)}
|
||||
<FileThumb data={data} />
|
||||
<View style={tw`mt-1 px-1.5 py-[1px]`}>
|
||||
<Text numberOfLines={1} style={tw`text-center text-xs font-medium text-white`}>
|
||||
{item?.name}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
import { ExplorerItem, ObjectKind, isObject } from '@sd/client';
|
||||
import { ExplorerItem } from '@sd/client';
|
||||
import { tw, twStyle } from '~/lib/tailwind';
|
||||
import { getExplorerStore } from '~/stores/explorerStore';
|
||||
import FileThumb from './FileThumb';
|
||||
|
@ -12,21 +12,13 @@ type FileRowProps = {
|
|||
const FileRow = ({ data }: FileRowProps) => {
|
||||
const { item } = data;
|
||||
|
||||
// temp fix (will handle this on mobile-inspector branch)
|
||||
const objectData = data ? (isObject(data) ? data.item : data.item.object) : null;
|
||||
const isVid = ObjectKind[objectData?.kind || 0] === 'Video';
|
||||
|
||||
return (
|
||||
<View
|
||||
style={twStyle('flex flex-row items-center px-3', {
|
||||
height: getExplorerStore().listItemSize
|
||||
})}
|
||||
>
|
||||
<FileThumb
|
||||
data={data}
|
||||
kind={item.extension === 'zip' ? 'zip' : isVid ? 'video' : 'other'}
|
||||
size={0.6}
|
||||
/>
|
||||
<FileThumb data={data} size={0.6} />
|
||||
<View style={tw`ml-3`}>
|
||||
<Text numberOfLines={1} style={tw`text-ink-dull text-center text-xs font-medium`}>
|
||||
{item?.name}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import * as icons from '@sd/assets/icons';
|
||||
import { PropsWithChildren } from 'react';
|
||||
import { Image, View } from 'react-native';
|
||||
import { DocumentDirectoryPath } from 'react-native-fs';
|
||||
import { ExplorerItem, isObject, isPath } from '@sd/client';
|
||||
// import icons from '../../assets/icons/file';
|
||||
import { ExplorerItem, ObjectKind, isObject, isPath } from '@sd/client';
|
||||
import { tw } from '../../lib/tailwind';
|
||||
import FolderIcon from '../icons/FolderIcon';
|
||||
|
||||
|
@ -13,112 +13,82 @@ type FileThumbProps = {
|
|||
* default: `1`
|
||||
*/
|
||||
size?: number;
|
||||
kind?: string;
|
||||
};
|
||||
|
||||
export const getThumbnailUrlById = (casId: string) =>
|
||||
`${DocumentDirectoryPath}/thumbnails/${encodeURIComponent(casId)}.webp`;
|
||||
|
||||
type KindType = keyof typeof icons | 'Unknown';
|
||||
|
||||
function getExplorerItemData(data: ExplorerItem) {
|
||||
const objectData = data ? (isObject(data) ? data.item : data.item.object) : null;
|
||||
|
||||
return {
|
||||
casId: (isObject(data) ? data.item.file_paths[0]?.cas_id : data.item.cas_id) || null,
|
||||
isDir: isPath(data) && data.item.is_dir,
|
||||
kind: ObjectKind[objectData?.kind || 0] as KindType,
|
||||
hasThumbnail: data.has_thumbnail,
|
||||
extension: data.item.extension
|
||||
};
|
||||
}
|
||||
|
||||
const FileThumbWrapper = ({ children, size = 1 }: PropsWithChildren<{ size: number }>) => (
|
||||
<View style={[tw`items-center justify-center`, { width: 80 * size, height: 80 * size }]}>
|
||||
{children}
|
||||
</View>
|
||||
);
|
||||
|
||||
export default function FileThumb({ data, size = 1, kind }: FileThumbProps) {
|
||||
// const Icon = useMemo(() => {
|
||||
// const Icon = icons[data.extension];
|
||||
// return Icon;
|
||||
// }, [data.extension]);
|
||||
export default function FileThumb({ data, size = 1 }: FileThumbProps) {
|
||||
const { casId, isDir, kind, hasThumbnail, extension } = getExplorerItemData(data);
|
||||
|
||||
if (isPath(data) && data.item.is_dir)
|
||||
if (isPath(data) && data.item.is_dir) {
|
||||
return (
|
||||
<FileThumbWrapper size={size}>
|
||||
<FolderIcon size={70 * size} />
|
||||
</FileThumbWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
const casId = isObject(data) ? data.item.file_paths[0]?.cas_id : data.item.cas_id;
|
||||
if (!casId) return null;
|
||||
|
||||
// Icon
|
||||
let icon = undefined;
|
||||
if (kind === 'Archive') icon = require('@sd/assets/images/Archive.png');
|
||||
else if (kind === 'Video') icon = require('@sd/assets/images/Video.png');
|
||||
else if (kind === 'Document' && data.item.extension === 'pdf')
|
||||
icon = require('@sd/assets/images/Document_pdf.png');
|
||||
else if (kind === 'Executable') icon = require('@sd/assets/images/Executable.png');
|
||||
|
||||
if (icon) {
|
||||
if (hasThumbnail && casId) {
|
||||
// TODO: Handle Image checkers bg?
|
||||
return (
|
||||
<FileThumbWrapper size={size}>
|
||||
<Image source={icon} style={{ width: 70 * size, height: 70 * size }} />
|
||||
<Image
|
||||
source={{ uri: getThumbnailUrlById(casId) }}
|
||||
resizeMode="contain"
|
||||
style={tw`h-full w-full`}
|
||||
/>
|
||||
</FileThumbWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
const url = getThumbnailUrlById(casId);
|
||||
// Default icon
|
||||
let icon = icons['Document'];
|
||||
|
||||
if (data.has_thumbnail && url) {
|
||||
return (
|
||||
<FileThumbWrapper size={size}>
|
||||
<Image source={{ uri: url }} resizeMode="contain" style={tw`h-full w-full`} />
|
||||
</FileThumbWrapper>
|
||||
);
|
||||
if (isDir) {
|
||||
icon = icons['Folder'];
|
||||
} else if (
|
||||
kind &&
|
||||
extension &&
|
||||
icons[`${kind}_${extension.toLowerCase()}` as keyof typeof icons]
|
||||
) {
|
||||
// e.g. Document_pdf
|
||||
icon = icons[`${kind}_${extension.toLowerCase()}` as keyof typeof icons];
|
||||
} else if (kind !== 'Unknown' && kind && icons[kind]) {
|
||||
icon = icons[kind];
|
||||
}
|
||||
|
||||
// TODO: Handle video thumbnails
|
||||
|
||||
// // 10 percent of the size
|
||||
// const videoBarsHeight = Math.floor(size / 10);
|
||||
|
||||
// // calculate 16:9 ratio for height from size
|
||||
// const videoHeight = Math.floor((size * 9) / 16) + videoBarsHeight * 2;
|
||||
|
||||
return (
|
||||
<FileThumbWrapper size={size}>
|
||||
<Image
|
||||
source={require('@sd/assets/images/File.png')}
|
||||
style={{ width: 70 * size, height: 70 * size }}
|
||||
/>
|
||||
<Image source={icon} style={{ width: 70 * size, height: 70 * size }} />
|
||||
</FileThumbWrapper>
|
||||
);
|
||||
|
||||
// Default file icon
|
||||
// return (
|
||||
// <View style={[tw`justify-center`, { width: 60 * size, height: 60 * size }]}>
|
||||
// <View style={[tw`m-auto relative`, { width: 45 * size, height: 60 * size }]}>
|
||||
// <Svg
|
||||
// // Background
|
||||
// style={tw`absolute top-0 left-0`}
|
||||
// fill={tw.color('app-box')}
|
||||
// width={45 * size}
|
||||
// height={60 * size}
|
||||
// viewBox="0 0 65 81"
|
||||
// >
|
||||
// <Path d="M0 8a8 8 0 0 1 8-8h31.686a8 8 0 0 1 5.657 2.343L53.5 10.5l9.157 9.157A8 8 0 0 1 65 25.314V73a8 8 0 0 1-8 8H8a8 8 0 0 1-8-8V8Z" />
|
||||
// </Svg>
|
||||
// <Svg
|
||||
// // Peel
|
||||
// style={tw`absolute top-[2px] -right-[0.6px]`}
|
||||
// fill={tw.color('app-highlight')}
|
||||
// width={15 * size}
|
||||
// height={15 * size}
|
||||
// viewBox="0 0 41 41"
|
||||
// >
|
||||
// <Path d="M41.412 40.558H11.234C5.03 40.558 0 35.528 0 29.324V0l41.412 40.558Z" />
|
||||
// </Svg>
|
||||
// {/* File Icon & Extension */}
|
||||
// <View style={tw`absolute w-full h-full items-center justify-center`}>
|
||||
// {Icon && (
|
||||
// <Suspense fallback={<></>}>
|
||||
// <Icon width={18 * size} height={18 * size} style={tw`mt-2`} />
|
||||
// </Suspense>
|
||||
// )}
|
||||
// <Text
|
||||
// style={[
|
||||
// tw`mt-1 font-bold text-center uppercase text-gray-450`,
|
||||
// {
|
||||
// fontSize: 10 * (size * 0.8)
|
||||
// }
|
||||
// ]}
|
||||
// >
|
||||
// {data.extension}
|
||||
// </Text>
|
||||
// </View>
|
||||
// </View>
|
||||
// </View>
|
||||
// );
|
||||
}
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
import { VariantProps, cva } from 'class-variance-authority';
|
||||
import { FC } from 'react';
|
||||
import { TextInputProps as RNTextInputProps, TextInput } from 'react-native';
|
||||
import { Eye, EyeSlash } from 'phosphor-react-native';
|
||||
import { useState } from 'react';
|
||||
import { Pressable, TextInputProps as RNTextInputProps, TextInput, View } from 'react-native';
|
||||
import { tw, twStyle } from '~/lib/tailwind';
|
||||
|
||||
const input = cva(['rounded-md border text-sm leading-tight shadow-sm'], {
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'border-app-line bg-app text-ink'
|
||||
default: 'border-app-line bg-app-input text-ink'
|
||||
},
|
||||
size: {
|
||||
default: ['py-2', 'px-3']
|
||||
default: ['py-2', 'px-3'],
|
||||
md: ['py-2.5', 'px-3.5']
|
||||
}
|
||||
},
|
||||
defaultVariants: {
|
||||
|
@ -20,13 +22,51 @@ const input = cva(['rounded-md border text-sm leading-tight shadow-sm'], {
|
|||
|
||||
type InputProps = VariantProps<typeof input> & RNTextInputProps;
|
||||
|
||||
export const Input: FC<InputProps> = ({ variant, ...props }) => {
|
||||
export const Input = ({ variant, size, ...props }: InputProps) => {
|
||||
const { style, ...otherProps } = props;
|
||||
return (
|
||||
<TextInput
|
||||
placeholderTextColor={tw.color('ink-dull')}
|
||||
style={twStyle(input({ variant }), style as string)}
|
||||
placeholderTextColor={tw.color('ink-faint')}
|
||||
style={twStyle(input({ variant, size }), style as string)}
|
||||
{...otherProps}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
// Same as above but configured with password props & show/hide password button
|
||||
|
||||
type PasswordInputProps = InputProps & {
|
||||
isNewPassword?: boolean;
|
||||
};
|
||||
|
||||
export const PasswordInput = ({ variant, size, ...props }: PasswordInputProps) => {
|
||||
const { style, isNewPassword = false, ...otherProps } = props;
|
||||
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
|
||||
const Icon = showPassword ? EyeSlash : Eye;
|
||||
|
||||
return (
|
||||
<View style={tw`relative`}>
|
||||
<TextInput
|
||||
autoComplete={isNewPassword ? 'password-new' : 'password'}
|
||||
textContentType={isNewPassword ? 'newPassword' : 'password'}
|
||||
placeholder="Password"
|
||||
secureTextEntry={!showPassword}
|
||||
autoCorrect={false}
|
||||
autoCapitalize="none"
|
||||
placeholderTextColor={tw.color('ink-dull')}
|
||||
// Do not use margin here, it will break the absolute positioning of the button.
|
||||
// Maybe switch to flexbox?
|
||||
style={twStyle(input({ variant, size }), style as string)}
|
||||
{...otherProps}
|
||||
/>
|
||||
<Pressable
|
||||
style={tw`absolute inset-y-[10px] right-4`}
|
||||
onPress={() => setShowPassword((v) => !v)}
|
||||
>
|
||||
<Icon size={18} color="white" />
|
||||
</Pressable>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { Folder } from '@sd/assets/icons';
|
||||
import FolderWhite from '@sd/assets/svgs/folder-white.svg';
|
||||
import { Image } from 'react-native';
|
||||
|
||||
|
@ -17,7 +18,7 @@ const FolderIcon: React.FC<FolderProps> = ({ size = 24, isWhite }) => {
|
|||
return isWhite ? (
|
||||
<FolderWhite width={size} height={size} />
|
||||
) : (
|
||||
<Image source={require('@sd/assets/images/Folder.png')} style={{ width: size, height: size }} />
|
||||
<Image source={Folder} style={{ width: size, height: size }} />
|
||||
);
|
||||
};
|
||||
|
||||
|
|
51
apps/mobile/src/components/key/PasswordMeter.tsx
Normal file
51
apps/mobile/src/components/key/PasswordMeter.tsx
Normal file
|
@ -0,0 +1,51 @@
|
|||
import { Text, View, ViewStyle } from 'react-native';
|
||||
import { getPasswordStrength } from '@sd/client';
|
||||
import { tw, twStyle } from '~/lib/tailwind';
|
||||
|
||||
// NOTE: Lazy load this component.
|
||||
|
||||
type PasswordMeterProps = {
|
||||
password: string;
|
||||
containerStyle?: ViewStyle;
|
||||
};
|
||||
|
||||
const PasswordMeter = (props: PasswordMeterProps) => {
|
||||
const { score, scoreText } = getPasswordStrength(props.password);
|
||||
|
||||
return (
|
||||
<View style={props.containerStyle}>
|
||||
<View style={tw`flex flex-row items-center justify-between`}>
|
||||
<Text style={tw`text-sm text-white`}>Password strength</Text>
|
||||
<Text
|
||||
style={twStyle(
|
||||
'text-sm font-semibold',
|
||||
score === 0 && 'text-red-500',
|
||||
score === 1 && 'text-red-500',
|
||||
score === 2 && 'text-amber-400',
|
||||
score === 3 && 'text-lime-500',
|
||||
score === 4 && 'text-accent'
|
||||
)}
|
||||
>
|
||||
{scoreText}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={tw`bg-app-box/80 mt-2 w-full rounded-full`}>
|
||||
<View
|
||||
style={twStyle(
|
||||
{
|
||||
width: `${score !== 0 ? score * 25 : 12.5}%`
|
||||
},
|
||||
'h-2 rounded-full',
|
||||
score === 0 && 'bg-red-500',
|
||||
score === 1 && 'bg-red-500',
|
||||
score === 2 && 'bg-amber-400',
|
||||
score === 3 && 'bg-lime-500',
|
||||
score === 4 && 'bg-accent'
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default PasswordMeter;
|
|
@ -11,7 +11,7 @@ const Card = ({ children, ...props }: CardProps) => {
|
|||
|
||||
return (
|
||||
<View
|
||||
style={twStyle('border-app-line bg-app-overlay rounded-lg border px-4 py-3', style as string)}
|
||||
style={twStyle('border-app-line bg-app-overlay rounded-lg border px-4 py-5', style as string)}
|
||||
{...otherProps}
|
||||
>
|
||||
{children}
|
||||
|
|
|
@ -95,8 +95,7 @@ const Dialog = (props: DialogProps) => {
|
|||
{props.loading && <PulseAnimation style={tw`h-7`} />}
|
||||
<View style={tw`grow`} />
|
||||
<Button
|
||||
variant="dark_gray"
|
||||
size="md"
|
||||
variant="darkGray"
|
||||
disabled={props.loading} // Disables Close button if loading
|
||||
onPress={handleCloseDialog}
|
||||
>
|
||||
|
@ -106,7 +105,6 @@ const Dialog = (props: DialogProps) => {
|
|||
<Button
|
||||
style={tw`ml-2`}
|
||||
variant={props.ctaDanger ? 'danger' : 'accent'}
|
||||
size="md"
|
||||
onPress={props.ctaAction}
|
||||
disabled={props.ctaDisabled || props.loading}
|
||||
>
|
||||
|
|
|
@ -132,13 +132,13 @@ const ImportModal = forwardRef<ModalRef, unknown>((_, ref) => {
|
|||
return (
|
||||
<Modal ref={modalRef} snapPoints={['25%']}>
|
||||
<View style={tw`flex-1 px-8 pt-8 pb-2`}>
|
||||
{/* <Button size="md" variant="accent" style={tw`my-2`} onPress={testFN}>
|
||||
{/* <Button variant="accent" style={tw`my-2`} onPress={testFN}>
|
||||
<Text>TEST</Text>
|
||||
</Button> */}
|
||||
<Button size="md" variant="accent" style={tw`my-2`} onPress={handleFilesButton}>
|
||||
<Button variant="accent" style={tw`my-2`} onPress={handleFilesButton}>
|
||||
<Text>Import from Files</Text>
|
||||
</Button>
|
||||
<Button size="md" variant="accent" onPress={handlePhotosButton}>
|
||||
<Button variant="accent" onPress={handlePhotosButton}>
|
||||
<Text>Import from Photos</Text>
|
||||
</Button>
|
||||
<Text style={tw`mt-4 text-center text-white`}>TODO</Text>
|
||||
|
|
|
@ -14,7 +14,7 @@ import { ExplorerItem, formatBytes, isObject, useLibraryQuery } from '@sd/client
|
|||
import FileThumb from '~/components/explorer/FileThumb';
|
||||
import InfoTagPills from '~/components/explorer/sections/InfoTagPills';
|
||||
import { Modal, ModalRef, ModalScrollView } from '~/components/layout/Modal';
|
||||
import Divider from '~/components/primitive/Divider';
|
||||
import { Divider } from '~/components/primitive/Divider';
|
||||
import useForwardedRef from '~/hooks/useForwardedRef';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
|
||||
|
|
|
@ -78,7 +78,6 @@ const CreateTagModal = forwardRef<ModalRef, unknown>((_, ref) => {
|
|||
)}
|
||||
<Button
|
||||
variant="accent"
|
||||
size="md"
|
||||
onPress={() => createTag({ color: tagColor, name: tagName })}
|
||||
style={tw`mt-6`}
|
||||
disabled={tagName.length === 0}
|
||||
|
|
|
@ -77,7 +77,6 @@ const UpdateTagModal = forwardRef<ModalRef, Props>((props, ref) => {
|
|||
{/* TODO: Add loading to button */}
|
||||
<Button
|
||||
variant="accent"
|
||||
size="md"
|
||||
onPress={() => updateTag({ id: props.tag.id, color: tagColor, name: tagName })}
|
||||
style={tw`mt-6`}
|
||||
disabled={tagName.length === 0}
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
import { VariantProps, cva } from 'class-variance-authority';
|
||||
import { MotiPressable, MotiPressableProps } from 'moti/interactions';
|
||||
import { FC, useMemo } from 'react';
|
||||
import { Pressable, PressableProps } from 'react-native';
|
||||
import { tw, twStyle } from '~/lib/tailwind';
|
||||
import { Pressable, PressableProps, View, ViewProps } from 'react-native';
|
||||
import { twStyle } from '~/lib/tailwind';
|
||||
|
||||
const button = cva(['items-center justify-center rounded-md border shadow-sm'], {
|
||||
variants: {
|
||||
variant: {
|
||||
danger: ['border-red-800 bg-red-600'],
|
||||
gray: ['border-app-line bg-app-button'],
|
||||
dark_gray: ['border-app-box bg-app'],
|
||||
accent: ['border-accent-deep bg-accent shadow-app-shade/10 shadow-md']
|
||||
darkGray: ['border-app-box bg-app'],
|
||||
accent: ['border-accent-deep bg-accent shadow-app-shade/10 shadow-md'],
|
||||
outline: ['border-sidebar-line/60 ']
|
||||
},
|
||||
size: {
|
||||
default: ['py-1', 'px-3'],
|
||||
default: ['py-1.5', 'px-3'],
|
||||
sm: ['py-1', 'px-2'],
|
||||
md: ['py-1.5', 'px-3'],
|
||||
lg: ['py-2', 'px-4']
|
||||
},
|
||||
disabled: {
|
||||
|
@ -70,3 +70,18 @@ export const AnimatedButton: FC<AnimatedButtonProps> = ({ variant, size, disable
|
|||
</MotiPressable>
|
||||
);
|
||||
};
|
||||
|
||||
// Useful for when you want to replicate a button but don't want to deal with the pressable logic (e.g. you need to disable the inner pressable)
|
||||
type FakeButtonProps = VariantProps<typeof button> & ViewProps;
|
||||
|
||||
export const FakeButton: FC<FakeButtonProps> = ({ variant, size, ...props }) => {
|
||||
const { style, ...otherProps } = props;
|
||||
return (
|
||||
<View
|
||||
style={twStyle(button({ variant, size, disabled: false }), style as string)}
|
||||
{...otherProps}
|
||||
>
|
||||
{props.children}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,12 +1,4 @@
|
|||
import { StyleProp, View, ViewStyle } from 'react-native';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
import { View } from 'react-native';
|
||||
import { styled } from '~/lib/tailwind';
|
||||
|
||||
type DividerProps = {
|
||||
style?: StyleProp<ViewStyle>;
|
||||
};
|
||||
|
||||
const Divider = ({ style }: DividerProps) => {
|
||||
return <View style={[tw`bg-app-line my-1 h-[1px] w-full`, style]} />;
|
||||
};
|
||||
|
||||
export default Divider;
|
||||
export const Divider = styled(View, 'bg-app-line my-1 h-[1px] w-full');
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { PropsWithChildren } from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
import { styled, tw } from '~/lib/tailwind';
|
||||
|
||||
type SettingsContainerProps = PropsWithChildren<{
|
||||
title?: string;
|
||||
|
@ -16,3 +16,6 @@ export function SettingsContainer({ children, title, description }: SettingsCont
|
|||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
export const SettingsInputTitle = styled(Text, 'text-ink mb-1.5 ml-1 text-sm font-medium');
|
||||
export const SettingsInputInfo = styled(Text, 'mt-2 text-xs text-ink-faint');
|
||||
|
|
|
@ -12,7 +12,7 @@ type SettingsItemProps = {
|
|||
export function SettingsItem(props: SettingsItemProps) {
|
||||
return (
|
||||
<Pressable onPress={props.onPress}>
|
||||
<View style={tw`bg-app-overlay flex flex-row items-center justify-between px-4`}>
|
||||
<View style={tw`bg-app-box flex flex-row items-center justify-between px-4`}>
|
||||
<View style={tw`flex flex-row items-center py-4`}>
|
||||
{props.leftIcon && props.leftIcon({ size: 20, color: tw.color('ink'), style: tw`mr-3` })}
|
||||
<Text style={tw`text-ink text-[14px]`}>{props.title}</Text>
|
||||
|
|
21
apps/mobile/src/hooks/useZodForm.ts
Normal file
21
apps/mobile/src/hooks/useZodForm.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { UseFormProps, useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
interface UseZodFormProps<S extends z.ZodSchema>
|
||||
extends Exclude<UseFormProps<z.infer<S>>, 'resolver'> {
|
||||
schema?: S;
|
||||
}
|
||||
|
||||
export const useZodForm = <S extends z.ZodSchema = z.ZodObject<Record<string, never>>>(
|
||||
props?: UseZodFormProps<S>
|
||||
) => {
|
||||
const { schema, ...formProps } = props ?? {};
|
||||
|
||||
return useForm({
|
||||
...formProps,
|
||||
resolver: zodResolver(schema || z.object({}))
|
||||
});
|
||||
};
|
||||
|
||||
export { z } from 'zod';
|
|
@ -1,7 +1,23 @@
|
|||
import React, { ComponentType } from 'react';
|
||||
import { create } from 'twrnc';
|
||||
|
||||
const tw = create(require(`../../tailwind.config.js`));
|
||||
|
||||
function styled<P>(Component: ComponentType<P>, baseStyles?: string) {
|
||||
return React.forwardRef<ComponentType<P>, P>(({ style, ...props }: any, ref) =>
|
||||
React.createElement(Component as any, {
|
||||
...props,
|
||||
style: twStyle(baseStyles, style),
|
||||
ref
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Same as clsx, this works with the eslint plugin (tailwindcss/classnames-order).
|
||||
const twStyle = tw.style;
|
||||
|
||||
export { tw, twStyle };
|
||||
tw.style = () => {
|
||||
throw new Error('Use twStyle instead of tw.style');
|
||||
};
|
||||
|
||||
export { tw, twStyle, styled };
|
||||
|
|
|
@ -9,6 +9,7 @@ SplashScreen.preventAutoHideAsync();
|
|||
const _localStorage = new Map<string, string>();
|
||||
|
||||
// We patch stuff onto `globalThis` so that `@sd/client` can use it. This is super hacky but as far as I can tell, there's no better way to do this.
|
||||
// TODO: Add env value to automatically set this to `true` in development and false in production builds.
|
||||
globalThis.isDev = true;
|
||||
|
||||
// Custom polyfill for browser `localStorage`
|
||||
|
|
|
@ -1,21 +1,37 @@
|
|||
import { StackScreenProps, createStackNavigator } from '@react-navigation/stack';
|
||||
import CreateLibraryScreen from '~/screens/onboarding/CreateLibrary';
|
||||
import OnboardingScreen from '~/screens/onboarding/Onboarding';
|
||||
import CreatingLibraryScreen from '~/screens/onboarding/CreatingLibrary';
|
||||
import GetStartedScreen from '~/screens/onboarding/GetStarted';
|
||||
import MasterPasswordScreen from '~/screens/onboarding/MasterPassword';
|
||||
import NewLibraryScreen from '~/screens/onboarding/NewLibrary';
|
||||
import PrivacyScreen from '~/screens/onboarding/Privacy';
|
||||
|
||||
const OnboardingStack = createStackNavigator<OnboardingStackParamList>();
|
||||
|
||||
export default function OnboardingNavigator() {
|
||||
return (
|
||||
<OnboardingStack.Navigator screenOptions={{ headerShown: false }}>
|
||||
<OnboardingStack.Screen name="Onboarding" component={OnboardingScreen} />
|
||||
<OnboardingStack.Screen name="CreateLibrary" component={CreateLibraryScreen} />
|
||||
<OnboardingStack.Navigator initialRouteName="GetStarted" screenOptions={{ headerShown: false }}>
|
||||
<OnboardingStack.Screen name="GetStarted" component={GetStartedScreen} />
|
||||
<OnboardingStack.Screen name="NewLibrary" component={NewLibraryScreen} />
|
||||
<OnboardingStack.Screen name="MasterPassword" component={MasterPasswordScreen} />
|
||||
<OnboardingStack.Screen name="Privacy" component={PrivacyScreen} />
|
||||
<OnboardingStack.Screen
|
||||
name="CreatingLibrary"
|
||||
component={CreatingLibraryScreen}
|
||||
options={{
|
||||
// Disable swipe back gesture
|
||||
gestureEnabled: false
|
||||
}}
|
||||
/>
|
||||
</OnboardingStack.Navigator>
|
||||
);
|
||||
}
|
||||
|
||||
export type OnboardingStackParamList = {
|
||||
Onboarding: undefined;
|
||||
CreateLibrary: undefined;
|
||||
GetStarted: undefined;
|
||||
NewLibrary: undefined;
|
||||
MasterPassword: undefined;
|
||||
Privacy: undefined;
|
||||
CreatingLibrary: undefined;
|
||||
};
|
||||
|
||||
export type OnboardingStackScreenProps<Screen extends keyof OnboardingStackParamList> =
|
||||
|
|
|
@ -8,6 +8,7 @@ import LibrarySettingsScreen from '~/screens/settings/client/LibrarySettings';
|
|||
import PrivacySettingsScreen from '~/screens/settings/client/PrivacySettings';
|
||||
import AboutScreen from '~/screens/settings/info/About';
|
||||
import SupportScreen from '~/screens/settings/info/Support';
|
||||
import EditLocationSettingsScreen from '~/screens/settings/library/EditLocationSettings';
|
||||
import KeysSettingsScreen from '~/screens/settings/library/KeysSettings';
|
||||
import LibraryGeneralSettingsScreen from '~/screens/settings/library/LibraryGeneralSettings';
|
||||
import LocationSettingsScreen from '~/screens/settings/library/LocationSettings';
|
||||
|
@ -71,6 +72,11 @@ export default function SettingsNavigator() {
|
|||
component={LocationSettingsScreen}
|
||||
options={{ headerTitle: 'Locations' }}
|
||||
/>
|
||||
<SettingsStack.Screen
|
||||
name="EditLocationSettings"
|
||||
component={EditLocationSettingsScreen}
|
||||
options={{ headerTitle: 'Edit Location' }}
|
||||
/>
|
||||
<SettingsStack.Screen
|
||||
name="NodesSettings"
|
||||
component={NodesSettingsScreen}
|
||||
|
@ -112,7 +118,11 @@ export type SettingsStackParamList = {
|
|||
ExtensionsSettings: undefined;
|
||||
// Library
|
||||
LibraryGeneralSettings: undefined;
|
||||
|
||||
// Location
|
||||
LocationSettings: undefined;
|
||||
EditLocationSettings: { id: number };
|
||||
|
||||
NodesSettings: undefined;
|
||||
TagsSettings: undefined;
|
||||
KeysSettings: undefined;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { BottomTabScreenProps, createBottomTabNavigator } from '@react-navigation/bottom-tabs';
|
||||
import { CompositeScreenProps, NavigatorScreenParams } from '@react-navigation/native';
|
||||
import { CirclesFour, Planet, ShareNetwork } from 'phosphor-react-native';
|
||||
import { Broadcast, CirclesFour, Planet, ShareNetwork } from 'phosphor-react-native';
|
||||
import React from 'react';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
import type { HomeDrawerScreenProps } from './DrawerNavigator';
|
||||
import NodesStack, { NodesStackParamList } from './tabs/NodesStack';
|
||||
import OverviewStack, { OverviewStackParamList } from './tabs/OverviewStack';
|
||||
import SpacedropStack, { SpacedropStackParamList } from './tabs/SpacedropStack';
|
||||
import SpacesStack, { SpacesStackParamList } from './tabs/SpacesStack';
|
||||
|
||||
const Tab = createBottomTabNavigator<TabParamList>();
|
||||
|
@ -39,21 +39,6 @@ export default function TabNavigator() {
|
|||
tabBarLabelStyle: tw`text-[10px] font-semibold`
|
||||
}}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name="NodesStack"
|
||||
component={NodesStack}
|
||||
options={{
|
||||
tabBarIcon: ({ focused }) => (
|
||||
<ShareNetwork
|
||||
size={22}
|
||||
weight={focused ? 'bold' : 'regular'}
|
||||
color={focused ? tw.color('accent') : tw.color('ink')}
|
||||
/>
|
||||
),
|
||||
tabBarLabel: 'Nodes',
|
||||
tabBarLabelStyle: tw`text-[10px] font-semibold`
|
||||
}}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name="SpacesStack"
|
||||
component={SpacesStack}
|
||||
|
@ -69,13 +54,28 @@ export default function TabNavigator() {
|
|||
tabBarLabelStyle: tw`text-[10px] font-semibold`
|
||||
}}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name="SpacedropStack"
|
||||
component={SpacedropStack}
|
||||
options={{
|
||||
tabBarIcon: ({ focused }) => (
|
||||
<Broadcast
|
||||
size={22}
|
||||
weight={focused ? 'bold' : 'regular'}
|
||||
color={focused ? tw.color('accent') : tw.color('ink')}
|
||||
/>
|
||||
),
|
||||
tabBarLabel: 'Spacedrop',
|
||||
tabBarLabelStyle: tw`text-[10px] font-semibold`
|
||||
}}
|
||||
/>
|
||||
</Tab.Navigator>
|
||||
);
|
||||
}
|
||||
|
||||
export type TabParamList = {
|
||||
OverviewStack: NavigatorScreenParams<OverviewStackParamList>;
|
||||
NodesStack: NavigatorScreenParams<NodesStackParamList>;
|
||||
SpacedropStack: NavigatorScreenParams<SpacedropStackParamList>;
|
||||
SpacesStack: NavigatorScreenParams<SpacesStackParamList>;
|
||||
};
|
||||
|
||||
|
|
|
@ -2,16 +2,16 @@ import { CompositeScreenProps } from '@react-navigation/native';
|
|||
import { StackScreenProps, createStackNavigator } from '@react-navigation/stack';
|
||||
import Header from '~/components/header/Header';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
import NodesScreen from '~/screens/Nodes';
|
||||
import SpacedropScreen from '~/screens/Spacedrop';
|
||||
import { SharedScreens, SharedScreensParamList } from '../SharedScreens';
|
||||
import { TabScreenProps } from '../TabNavigator';
|
||||
|
||||
const Stack = createStackNavigator<NodesStackParamList>();
|
||||
const Stack = createStackNavigator<SpacedropStackParamList>();
|
||||
|
||||
export default function NodesStack() {
|
||||
export default function SpacedropStack() {
|
||||
return (
|
||||
<Stack.Navigator
|
||||
initialRouteName="Nodes"
|
||||
initialRouteName="Spacedrop"
|
||||
screenOptions={{
|
||||
headerStyle: { backgroundColor: tw.color('app-box') },
|
||||
headerTintColor: tw.color('ink'),
|
||||
|
@ -19,17 +19,18 @@ export default function NodesStack() {
|
|||
headerBackTitleStyle: tw`text-base`
|
||||
}}
|
||||
>
|
||||
<Stack.Screen name="Nodes" component={NodesScreen} options={{ header: Header }} />
|
||||
<Stack.Screen name="Spacedrop" component={SpacedropScreen} options={{ header: Header }} />
|
||||
{SharedScreens(Stack as any)}
|
||||
</Stack.Navigator>
|
||||
);
|
||||
}
|
||||
|
||||
export type NodesStackParamList = {
|
||||
Nodes: undefined;
|
||||
export type SpacedropStackParamList = {
|
||||
Spacedrop: undefined;
|
||||
} & SharedScreensParamList;
|
||||
|
||||
export type NodesStackScreenProps<Screen extends keyof NodesStackParamList> = CompositeScreenProps<
|
||||
StackScreenProps<NodesStackParamList, Screen>,
|
||||
TabScreenProps<'NodesStack'>
|
||||
>;
|
||||
export type SpacedropStackScreenProps<Screen extends keyof SpacedropStackParamList> =
|
||||
CompositeScreenProps<
|
||||
StackScreenProps<SpacedropStackParamList, Screen>,
|
||||
TabScreenProps<'SpacedropStack'>
|
||||
>;
|
|
@ -1,11 +0,0 @@
|
|||
import { Text, View } from 'react-native';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
import { NodesStackScreenProps } from '~/navigation/tabs/NodesStack';
|
||||
|
||||
export default function NodesScreen({ navigation }: NodesStackScreenProps<'Nodes'>) {
|
||||
return (
|
||||
<View style={tw`flex-1 items-center justify-center`}>
|
||||
<Text style={tw`text-ink text-xl font-bold`}>Nodes</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
141
apps/mobile/src/screens/Spacedrop.tsx
Normal file
141
apps/mobile/src/screens/Spacedrop.tsx
Normal file
|
@ -0,0 +1,141 @@
|
|||
import { GoogleDrive, Mega, iCloud } from '@sd/assets/images';
|
||||
import { DeviceMobile, Icon, Laptop, User } from 'phosphor-react-native';
|
||||
import { Alert, Image, ImageSourcePropType, Pressable, ScrollView, Text, View } from 'react-native';
|
||||
import { Polygon, Svg } from 'react-native-svg';
|
||||
import { InfoPill } from '~/components/primitive/InfoPill';
|
||||
import { tw, twStyle } from '~/lib/tailwind';
|
||||
import { SpacedropStackScreenProps } from '~/navigation/tabs/SpacedropStack';
|
||||
|
||||
const testData = [
|
||||
{
|
||||
name: "Jamie's MacBook Pro",
|
||||
receivingNodeOsType: 'macOS',
|
||||
connectionType: 'lan',
|
||||
icon: Laptop
|
||||
},
|
||||
{
|
||||
name: "Jamie's MacBook Pro",
|
||||
receivingNodeOsType: 'iOS',
|
||||
connectionType: 'lan',
|
||||
icon: DeviceMobile
|
||||
},
|
||||
{
|
||||
name: 'Brendan Alan',
|
||||
image: 'https://github.com/brendonovich.png',
|
||||
connectionType: 'p2p'
|
||||
},
|
||||
{
|
||||
name: 'Oscar Beaumont',
|
||||
image: 'https://github.com/oscartbeaumont.png',
|
||||
connectionType: 'usb'
|
||||
},
|
||||
{
|
||||
name: 'maxichrome',
|
||||
image: 'https://github.com/maxichrome.png',
|
||||
connectionType: 'p2p'
|
||||
},
|
||||
{
|
||||
name: 'Utku',
|
||||
image: 'https://github.com/utkubakir.png',
|
||||
connectionType: 'p2p'
|
||||
},
|
||||
{ name: "Jamie's Google Drive", brandIcon: 'google-drive', connectionType: 'cloud' },
|
||||
{ name: 'iCloud', brandIcon: 'icloud', connectionType: 'cloud' },
|
||||
{ name: 'Mega', brandIcon: 'mega', connectionType: 'cloud' }
|
||||
] as DropItemProps[];
|
||||
|
||||
const Hexagon = () => {
|
||||
const width = 180;
|
||||
const height = width * 1.1547;
|
||||
|
||||
return (
|
||||
<Svg width={width} height={height} viewBox="0 0 100 100">
|
||||
<Polygon points="0,25 0,75 50,100 100,75 100,25 50,0" fill={tw.color('bg-app-box/30')} />
|
||||
</Svg>
|
||||
);
|
||||
};
|
||||
|
||||
type OperatingSystem = 'browser' | 'linux' | 'macOS' | 'windows' | 'iOS' | 'android';
|
||||
|
||||
type DropItemProps = {
|
||||
name: string;
|
||||
connectionType: 'lan' | 'bluetooth' | 'usb' | 'p2p' | 'cloud';
|
||||
receivingNodeOsType: OperatingSystem;
|
||||
} & ({ image: string } | { icon: Icon } | { brandIcon: string });
|
||||
|
||||
function DropItem(props: DropItemProps) {
|
||||
let icon;
|
||||
if ('image' in props) {
|
||||
icon = <Image style={tw`h-12 w-12 rounded-full`} source={{ uri: props.image }} />;
|
||||
} else if ('brandIcon' in props) {
|
||||
let brandIconSrc: ImageSourcePropType | undefined;
|
||||
switch (props.brandIcon) {
|
||||
case 'google-drive':
|
||||
brandIconSrc = GoogleDrive;
|
||||
break;
|
||||
case 'icloud':
|
||||
brandIconSrc = iCloud;
|
||||
break;
|
||||
case 'mega':
|
||||
brandIconSrc = Mega;
|
||||
break;
|
||||
}
|
||||
if (!brandIconSrc) throw new Error('Invalid brand icon url: ' + props.brandIcon);
|
||||
icon = (
|
||||
<View style={tw`flex items-center justify-center p-3`}>
|
||||
{/* // Needs width and height */}
|
||||
<Image source={brandIconSrc} style={tw`h-8 w-8 rounded-full`} />
|
||||
</View>
|
||||
);
|
||||
} else {
|
||||
// Use the custom icon or default to User icon.
|
||||
const Icon = props.icon || User;
|
||||
icon = <Icon size={30} color="white" style={twStyle(!props.name && 'opacity-20')} />;
|
||||
}
|
||||
return (
|
||||
<View style={tw`relative`}>
|
||||
<Hexagon />
|
||||
<View style={tw`absolute h-full w-full items-center justify-center`}>
|
||||
<Pressable
|
||||
style={tw`w-full items-center justify-center`}
|
||||
onPress={() => Alert.alert('TODO')}
|
||||
>
|
||||
<View style={tw`bg-app-button h-12 w-12 items-center justify-center rounded-full`}>
|
||||
{icon}
|
||||
</View>
|
||||
{props.name && (
|
||||
<Text numberOfLines={1} style={tw`mt-1 text-sm font-medium text-white`}>
|
||||
{props.name}
|
||||
</Text>
|
||||
)}
|
||||
<View style={tw`mt-1 flex flex-row gap-x-1`}>
|
||||
{props.receivingNodeOsType && <InfoPill text={props.receivingNodeOsType} />}
|
||||
{props.connectionType && (
|
||||
<InfoPill
|
||||
text={props.connectionType}
|
||||
containerStyle={twStyle(
|
||||
'px-1',
|
||||
props.connectionType === 'lan' && 'bg-green-500',
|
||||
props.connectionType === 'p2p' && 'bg-blue-500'
|
||||
)}
|
||||
textStyle={tw`uppercase text-white`}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</Pressable>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
export default function SpacedropScreen({ navigation }: SpacedropStackScreenProps<'Spacedrop'>) {
|
||||
return (
|
||||
<View style={tw`flex-1 py-4`}>
|
||||
<ScrollView contentContainerStyle={tw`flex flex-row flex-wrap justify-center gap-x-2`}>
|
||||
{testData.map((item, i) => (
|
||||
<DropItem key={i} {...item} />
|
||||
))}
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
import { Text, View } from 'react-native';
|
||||
import CreateLibraryDialog from '~/components/dialog/CreateLibraryDialog';
|
||||
import { AnimatedButton } from '~/components/primitive/Button';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
import { OnboardingStackScreenProps } from '~/navigation/OnboardingNavigator';
|
||||
|
||||
const CreateLibraryScreen = ({ navigation }: OnboardingStackScreenProps<'CreateLibrary'>) => {
|
||||
return (
|
||||
<View style={tw`bg-app flex-1 items-center justify-center p-4`}>
|
||||
<Text style={tw`text-ink-dull my-8 px-6 text-center text-base leading-relaxed`}>
|
||||
Onboarding screen for users to create their first library
|
||||
</Text>
|
||||
<CreateLibraryDialog disableBackdropClose>
|
||||
<AnimatedButton variant="accent">
|
||||
<Text style={tw`text-ink px-6 py-2 text-center text-base font-medium`}>
|
||||
Create Library
|
||||
</Text>
|
||||
</AnimatedButton>
|
||||
</CreateLibraryDialog>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default CreateLibraryScreen;
|
87
apps/mobile/src/screens/onboarding/CreatingLibrary.tsx
Normal file
87
apps/mobile/src/screens/onboarding/CreatingLibrary.tsx
Normal file
|
@ -0,0 +1,87 @@
|
|||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { Text } from 'react-native';
|
||||
import {
|
||||
HASHING_ALGOS,
|
||||
resetOnboardingStore,
|
||||
telemetryStore,
|
||||
useBridgeMutation,
|
||||
useDebugState,
|
||||
useOnboardingStore
|
||||
} from '@sd/client';
|
||||
import { PulseAnimation } from '~/components/animation/lottie';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
import { OnboardingStackScreenProps } from '~/navigation/OnboardingNavigator';
|
||||
import { currentLibraryStore } from '~/utils/nav';
|
||||
import { OnboardingContainer, OnboardingDescription, OnboardingTitle } from './GetStarted';
|
||||
|
||||
const CreatingLibraryScreen = ({ navigation }: OnboardingStackScreenProps<'CreatingLibrary'>) => {
|
||||
const [status, setStatus] = useState('Creating your library...');
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const debugState = useDebugState();
|
||||
const obStore = useOnboardingStore();
|
||||
|
||||
const createLibrary = useBridgeMutation('library.create', {
|
||||
onSuccess: (lib) => {
|
||||
resetOnboardingStore();
|
||||
queryClient.setQueryData(['library.list'], (libraries: any) => [...(libraries || []), lib]);
|
||||
// Switch to the new library
|
||||
currentLibraryStore.id = lib.uuid;
|
||||
},
|
||||
onError: () => {
|
||||
// TODO: Show toast
|
||||
resetOnboardingStore();
|
||||
navigation.navigate('GetStarted');
|
||||
}
|
||||
});
|
||||
|
||||
const created = useRef(false);
|
||||
|
||||
const create = async () => {
|
||||
telemetryStore.shareTelemetry = obStore.shareTelemetry;
|
||||
|
||||
createLibrary.mutate({
|
||||
name: obStore.newLibraryName,
|
||||
auth: {
|
||||
type: 'TokenizedPassword',
|
||||
value: obStore.passwordSetToken || ''
|
||||
},
|
||||
algorithm: obStore.algorithm,
|
||||
hashing_algorithm: HASHING_ALGOS[obStore.hashingAlgorithm]
|
||||
});
|
||||
|
||||
return;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (created.current == true) return;
|
||||
created.current = true;
|
||||
create();
|
||||
const timer = setTimeout(() => {
|
||||
setStatus('Almost done...');
|
||||
}, 2000);
|
||||
const timer2 = setTimeout(() => {
|
||||
if (debugState.enabled) {
|
||||
setStatus(`You're running in development, this will take longer...`);
|
||||
}
|
||||
}, 5000);
|
||||
return () => {
|
||||
clearTimeout(timer);
|
||||
clearTimeout(timer2);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<OnboardingContainer>
|
||||
<Text style={tw`mb-4 text-5xl`}>🛠</Text>
|
||||
<OnboardingTitle>Creating your library</OnboardingTitle>
|
||||
<OnboardingDescription style={tw`mt-4`}>{status}</OnboardingDescription>
|
||||
<PulseAnimation style={tw`mt-2 h-10`} speed={0.3} />
|
||||
</OnboardingContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default CreatingLibraryScreen;
|
82
apps/mobile/src/screens/onboarding/GetStarted.tsx
Normal file
82
apps/mobile/src/screens/onboarding/GetStarted.tsx
Normal file
|
@ -0,0 +1,82 @@
|
|||
import { AppLogo, BloomOne } from '@sd/assets/images';
|
||||
import { useNavigation, useRoute } from '@react-navigation/native';
|
||||
import { CaretLeft } from 'phosphor-react-native';
|
||||
import { Image, KeyboardAvoidingView, Platform, Pressable, Text, View } from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { FadeInUpAnimation, LogoAnimation } from '~/components/animation/layout';
|
||||
import { AnimatedButton } from '~/components/primitive/Button';
|
||||
import { styled, tw, twStyle } from '~/lib/tailwind';
|
||||
import { OnboardingStackScreenProps } from '~/navigation/OnboardingNavigator';
|
||||
|
||||
export function OnboardingContainer({ children }: React.PropsWithChildren) {
|
||||
const navigation = useNavigation();
|
||||
const route = useRoute();
|
||||
|
||||
const { top, bottom } = useSafeAreaInsets();
|
||||
|
||||
return (
|
||||
<View style={tw`flex-1`}>
|
||||
{route.name !== 'GetStarted' && route.name !== 'CreatingLibrary' && (
|
||||
<Pressable
|
||||
style={twStyle('absolute left-6 z-50', { top: top + 16 })}
|
||||
onPress={() => navigation.goBack()}
|
||||
>
|
||||
<CaretLeft size={24} weight="bold" color="white" />
|
||||
</Pressable>
|
||||
)}
|
||||
<View style={tw`z-10 flex-1 items-center justify-center`}>
|
||||
<KeyboardAvoidingView
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||
keyboardVerticalOffset={bottom}
|
||||
style={tw`w-full flex-1 items-center justify-center px-4`}
|
||||
>
|
||||
{children}
|
||||
</KeyboardAvoidingView>
|
||||
<Text style={tw`text-ink-dull/50 absolute bottom-8 text-xs`}>
|
||||
© 2022 Spacedrive Technology Inc.
|
||||
</Text>
|
||||
</View>
|
||||
{/* Bloom */}
|
||||
<Image source={BloomOne} style={tw`top-100 absolute h-screen w-screen opacity-20`} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
export const OnboardingTitle = styled(
|
||||
Text,
|
||||
'text-ink text-center text-4xl font-extrabold leading-tight'
|
||||
);
|
||||
|
||||
export const OnboardingDescription = styled(
|
||||
Text,
|
||||
'text-ink-dull text-center text-base leading-relaxed'
|
||||
);
|
||||
|
||||
const GetStartedScreen = ({ navigation }: OnboardingStackScreenProps<'GetStarted'>) => {
|
||||
return (
|
||||
<OnboardingContainer>
|
||||
{/* Logo */}
|
||||
<LogoAnimation style={tw`items-center`}>
|
||||
<Image source={AppLogo} style={tw`h-30 w-30`} />
|
||||
</LogoAnimation>
|
||||
{/* Title */}
|
||||
<FadeInUpAnimation delay={500} style={tw`mt-8`}>
|
||||
<OnboardingTitle>The file explorer from the future.</OnboardingTitle>
|
||||
</FadeInUpAnimation>
|
||||
{/* Description */}
|
||||
<FadeInUpAnimation delay={800} style={tw`mt-8`}>
|
||||
<OnboardingDescription style={tw`px-4`}>
|
||||
Welcome to Spacedrive, an open source cross-platform file manager.
|
||||
</OnboardingDescription>
|
||||
</FadeInUpAnimation>
|
||||
{/* Get Started Button */}
|
||||
<FadeInUpAnimation delay={1200} style={tw`mt-8`}>
|
||||
<AnimatedButton variant="accent" onPress={() => navigation.push('NewLibrary')}>
|
||||
<Text style={tw`text-ink text-center text-base font-medium`}>Get Started</Text>
|
||||
</AnimatedButton>
|
||||
</FadeInUpAnimation>
|
||||
</OnboardingContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default GetStartedScreen;
|
151
apps/mobile/src/screens/onboarding/MasterPassword.tsx
Normal file
151
apps/mobile/src/screens/onboarding/MasterPassword.tsx
Normal file
|
@ -0,0 +1,151 @@
|
|||
import React, { lazy, useState } from 'react';
|
||||
import { Controller } from 'react-hook-form';
|
||||
import { Alert, Text, View } from 'react-native';
|
||||
import { getOnboardingStore, useBridgeMutation, useOnboardingStore } from '@sd/client';
|
||||
import { PasswordInput } from '~/components/form/Input';
|
||||
import { Button } from '~/components/primitive/Button';
|
||||
import { useZodForm, z } from '~/hooks/useZodForm';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
import { OnboardingStackScreenProps } from '~/navigation/OnboardingNavigator';
|
||||
import { OnboardingContainer, OnboardingDescription, OnboardingTitle } from './GetStarted';
|
||||
|
||||
const PasswordMeter = lazy(() => import('~/components/key/PasswordMeter'));
|
||||
|
||||
const schema = z.object({
|
||||
password: z.string(),
|
||||
password_validate: z.string(),
|
||||
algorithm: z.string(),
|
||||
hashing_algorithm: z.string()
|
||||
});
|
||||
|
||||
const MasterPasswordScreen = ({ navigation }: OnboardingStackScreenProps<'MasterPassword'>) => {
|
||||
const [showPasswordValidate, setShowPasswordValidate] = useState(false);
|
||||
|
||||
const obStore = useOnboardingStore();
|
||||
|
||||
const form = useZodForm({
|
||||
schema,
|
||||
defaultValues: {
|
||||
password: '',
|
||||
password_validate: '',
|
||||
algorithm: 'XChaCha20Poly1305',
|
||||
hashing_algorithm: 'Argon2id-s'
|
||||
}
|
||||
});
|
||||
|
||||
const tokenizeSensitiveKey = useBridgeMutation('nodes.tokenizeSensitiveKey', {
|
||||
onSuccess: (data) => {
|
||||
getOnboardingStore().passwordSetToken = data.token;
|
||||
navigation.navigate('Privacy');
|
||||
},
|
||||
onError: (err: any) => {
|
||||
Alert.alert(err);
|
||||
}
|
||||
});
|
||||
|
||||
const handleSetPassword = form.handleSubmit(async (data) => {
|
||||
if (data.password !== data.password_validate) {
|
||||
if (!showPasswordValidate) {
|
||||
setShowPasswordValidate(true);
|
||||
// focus on confirm password field
|
||||
} else {
|
||||
form.setError('password_validate', {
|
||||
type: 'manual',
|
||||
message: 'Passwords do not match'
|
||||
});
|
||||
}
|
||||
} else {
|
||||
tokenizeSensitiveKey.mutate({
|
||||
secret_key: data.password
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const handleNoPassword = form.handleSubmit(async (data) => {
|
||||
tokenizeSensitiveKey.mutate({ secret_key: '' });
|
||||
});
|
||||
|
||||
const password = form.watch('password');
|
||||
|
||||
return (
|
||||
<OnboardingContainer>
|
||||
<OnboardingTitle>Set a master password</OnboardingTitle>
|
||||
<OnboardingDescription style={tw`mt-4`}>
|
||||
This will be used to encrypt your library and/or open the built-in key manager.
|
||||
</OnboardingDescription>
|
||||
<View style={tw`w-full`}>
|
||||
<View style={tw`mt-4 mb-2`}>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="password"
|
||||
render={({ field: { onBlur, onChange, value } }) => (
|
||||
<PasswordInput onChangeText={onChange} onBlur={onBlur} value={value} isNewPassword />
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
{showPasswordValidate && (
|
||||
<View style={tw`my-2`}>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="password_validate"
|
||||
render={({ field: { onBlur, onChange, value } }) => (
|
||||
<PasswordInput
|
||||
onChangeText={onChange}
|
||||
onBlur={onBlur}
|
||||
value={value}
|
||||
placeholder="Confirm password"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
{form.formState.errors.password_validate && (
|
||||
<Text style={tw`my-2 text-center text-xs font-bold text-red-500`}>
|
||||
{form.formState.errors.password_validate.message}
|
||||
</Text>
|
||||
)}
|
||||
<PasswordMeter containerStyle={tw`mt-3 px-2`} password={form.watch('password')} />
|
||||
<View style={tw`mt-6`}>
|
||||
{password.length > 0 && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={form.formState.isSubmitting}
|
||||
onPress={handleSetPassword}
|
||||
>
|
||||
<Text style={tw`text-ink text-center font-medium`}>
|
||||
{!showPasswordValidate ? 'Set password' : 'Confirm Password'}
|
||||
</Text>
|
||||
</Button>
|
||||
)}
|
||||
<View style={tw`mt-4`}>
|
||||
{obStore.passwordSetToken ? (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={form.formState.isSubmitting}
|
||||
onPress={() => {
|
||||
getOnboardingStore().passwordSetToken = null;
|
||||
form.reset();
|
||||
}}
|
||||
>
|
||||
<Text style={tw`text-ink text-center font-medium`}>Remove password</Text>
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={form.formState.isSubmitting}
|
||||
onPress={handleNoPassword}
|
||||
>
|
||||
<Text style={tw`text-ink text-center font-medium`}>Continue without password</Text>
|
||||
</Button>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</OnboardingContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default MasterPasswordScreen;
|
77
apps/mobile/src/screens/onboarding/NewLibrary.tsx
Normal file
77
apps/mobile/src/screens/onboarding/NewLibrary.tsx
Normal file
|
@ -0,0 +1,77 @@
|
|||
import { Database } from '@sd/assets/icons';
|
||||
import { Controller } from 'react-hook-form';
|
||||
import { Alert, Image, Text, View } from 'react-native';
|
||||
import { getOnboardingStore, useOnboardingStore } from '@sd/client';
|
||||
import { Input } from '~/components/form/Input';
|
||||
import { Button } from '~/components/primitive/Button';
|
||||
import { useZodForm, z } from '~/hooks/useZodForm';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
import { OnboardingStackScreenProps } from '~/navigation/OnboardingNavigator';
|
||||
import { OnboardingContainer, OnboardingDescription, OnboardingTitle } from './GetStarted';
|
||||
|
||||
const schema = z.object({
|
||||
name: z.string().min(1, { message: 'Library name is required' })
|
||||
});
|
||||
|
||||
const NewLibraryScreen = ({ navigation }: OnboardingStackScreenProps<'NewLibrary'>) => {
|
||||
const obStore = useOnboardingStore();
|
||||
|
||||
const form = useZodForm({
|
||||
schema,
|
||||
defaultValues: {
|
||||
name: obStore.newLibraryName
|
||||
}
|
||||
});
|
||||
|
||||
const handleNewLibrary = form.handleSubmit(async (data) => {
|
||||
getOnboardingStore().newLibraryName = data.name;
|
||||
navigation.navigate('MasterPassword');
|
||||
});
|
||||
|
||||
const handleImport = () => {
|
||||
Alert.alert('TODO');
|
||||
};
|
||||
|
||||
return (
|
||||
<OnboardingContainer>
|
||||
<Image source={Database} style={tw`h-25 w-25`} />
|
||||
<OnboardingTitle style={tw`mt-4`}>Create a Library</OnboardingTitle>
|
||||
<View style={tw`w-full px-4`}>
|
||||
<OnboardingDescription style={tw`mt-4`}>
|
||||
Libraries are a secure, on-device database. Your files remain where they are, the Library
|
||||
catalogs them and stores all Spacedrive related data.
|
||||
</OnboardingDescription>
|
||||
<Controller
|
||||
name="name"
|
||||
control={form.control}
|
||||
render={({ field: { onBlur, onChange, value } }) => (
|
||||
<Input
|
||||
style={tw`my-3`}
|
||||
placeholder='e.g. "James Library"'
|
||||
onBlur={onBlur}
|
||||
onChangeText={onChange}
|
||||
value={value}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{form.formState.errors.name && (
|
||||
<Text style={tw`text-center text-xs font-bold text-red-500`}>
|
||||
{form.formState.errors.name.message}
|
||||
</Text>
|
||||
)}
|
||||
<View style={tw`mt-4 flex w-full flex-row items-center justify-center`}>
|
||||
<Button variant="accent" onPress={handleNewLibrary}>
|
||||
<Text style={tw`text-ink text-center font-medium`}>New Library</Text>
|
||||
</Button>
|
||||
<Text style={tw`text-ink-faint px-4 text-xs font-bold`}>OR</Text>
|
||||
<Button onPress={handleImport} variant="outline">
|
||||
<Text style={tw`text-ink text-center font-medium`}>Import Library</Text>
|
||||
</Button>
|
||||
</View>
|
||||
</OnboardingContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default NewLibraryScreen;
|
|
@ -1,41 +0,0 @@
|
|||
import { AppLogo } from '@sd/assets/images';
|
||||
import { Image, Text, View } from 'react-native';
|
||||
import { FadeInUpAnimation, LogoAnimation } from '~/components/animation/layout';
|
||||
import { AnimatedButton } from '~/components/primitive/Button';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
import { OnboardingStackScreenProps } from '~/navigation/OnboardingNavigator';
|
||||
|
||||
const OnboardingScreen = ({ navigation }: OnboardingStackScreenProps<'Onboarding'>) => {
|
||||
return (
|
||||
<View style={tw`bg-app z-10 flex-1 items-center justify-around p-4`}>
|
||||
{/* Logo */}
|
||||
<LogoAnimation>
|
||||
<View style={tw`mt-2 items-center`}>
|
||||
<Image source={AppLogo} style={tw`h-24 w-24`} />
|
||||
</View>
|
||||
</LogoAnimation>
|
||||
{/* Text */}
|
||||
<View>
|
||||
<FadeInUpAnimation delay={500}>
|
||||
<Text style={tw`text-ink text-center text-5xl font-black leading-tight`}>
|
||||
A file explorer from the future.
|
||||
</Text>
|
||||
</FadeInUpAnimation>
|
||||
<FadeInUpAnimation delay={800}>
|
||||
<Text style={tw`text-ink-dull mt-8 px-6 text-center text-base leading-relaxed`}>
|
||||
Combine your drives and clouds into one database that you can organize and explore from
|
||||
any device.
|
||||
</Text>
|
||||
</FadeInUpAnimation>
|
||||
</View>
|
||||
{/* Get Started Button */}
|
||||
<FadeInUpAnimation delay={1200}>
|
||||
<AnimatedButton variant="accent" onPress={() => navigation.navigate('CreateLibrary')}>
|
||||
<Text style={tw`text-ink px-6 py-2 text-center text-base font-medium`}>Get Started</Text>
|
||||
</AnimatedButton>
|
||||
</FadeInUpAnimation>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default OnboardingScreen;
|
82
apps/mobile/src/screens/onboarding/Privacy.tsx
Normal file
82
apps/mobile/src/screens/onboarding/Privacy.tsx
Normal file
|
@ -0,0 +1,82 @@
|
|||
import React, { useState } from 'react';
|
||||
import { Pressable, Text, View, ViewStyle } from 'react-native';
|
||||
import { getOnboardingStore } from '@sd/client';
|
||||
import { Button } from '~/components/primitive/Button';
|
||||
import { tw, twStyle } from '~/lib/tailwind';
|
||||
import { OnboardingStackScreenProps } from '~/navigation/OnboardingNavigator';
|
||||
import { OnboardingContainer, OnboardingDescription, OnboardingTitle } from './GetStarted';
|
||||
|
||||
type RadioButtonProps = {
|
||||
title: string;
|
||||
description: string;
|
||||
isSelected: boolean;
|
||||
style?: ViewStyle;
|
||||
};
|
||||
|
||||
// Make this a component?
|
||||
const RadioButton = ({ title, description, isSelected, style }: RadioButtonProps) => {
|
||||
return (
|
||||
<View
|
||||
style={twStyle(
|
||||
'border-app-line bg-app-box/50 flex w-full flex-row items-center rounded-md border p-3',
|
||||
style
|
||||
)}
|
||||
>
|
||||
<View
|
||||
style={twStyle(
|
||||
'mr-2.5 h-5 w-5 items-center justify-center rounded-full',
|
||||
isSelected ? 'bg-accent' : 'bg-gray-900'
|
||||
)}
|
||||
>
|
||||
{isSelected && <View style={tw`h-1.5 w-1.5 rounded-full bg-white`} />}
|
||||
</View>
|
||||
<View style={tw`flex-1`}>
|
||||
<Text style={tw`text-ink text-base font-bold`}>{title}</Text>
|
||||
<Text style={tw`text-ink-faint text-sm`}>{description}</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const PrivacyScreen = ({ navigation }: OnboardingStackScreenProps<'Privacy'>) => {
|
||||
const [shareTelemetry, setShareTelemetry] = useState<'share-telemetry' | 'no-share-telemetry'>(
|
||||
'share-telemetry'
|
||||
);
|
||||
|
||||
const onPress = () => {
|
||||
getOnboardingStore().shareTelemetry = shareTelemetry === 'share-telemetry';
|
||||
navigation.navigate('CreatingLibrary');
|
||||
};
|
||||
|
||||
return (
|
||||
<OnboardingContainer>
|
||||
<OnboardingTitle>Your Privacy</OnboardingTitle>
|
||||
<OnboardingDescription style={tw`mt-4`}>
|
||||
Spacedrive is built for privacy, that's why we're open source and local first. So we'll make
|
||||
it very clear what data is shared with us.
|
||||
</OnboardingDescription>
|
||||
<View style={tw`w-full`}>
|
||||
<Pressable onPress={() => setShareTelemetry('share-telemetry')}>
|
||||
<RadioButton
|
||||
title="Share anonymous usage"
|
||||
description="Share completely anonymous telemetry data to help the developers improve the app"
|
||||
isSelected={shareTelemetry === 'share-telemetry'}
|
||||
style={tw`mt-4 mb-3`}
|
||||
/>
|
||||
</Pressable>
|
||||
<Pressable onPress={() => setShareTelemetry('no-share-telemetry')}>
|
||||
<RadioButton
|
||||
title="Share nothing"
|
||||
description="Do not share any telemetry data with the developers"
|
||||
isSelected={shareTelemetry === 'no-share-telemetry'}
|
||||
/>
|
||||
</Pressable>
|
||||
</View>
|
||||
<Button variant="accent" size="sm" onPress={onPress} style={tw`mt-6`}>
|
||||
<Text style={tw`text-ink text-center text-base font-medium`}>Continue</Text>
|
||||
</Button>
|
||||
</OnboardingContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default PrivacyScreen;
|
|
@ -109,7 +109,7 @@ function renderSectionHeader({ section }: { section: { title: string } }) {
|
|||
return (
|
||||
<Text
|
||||
style={twStyle(
|
||||
'text-ink-dull mb-2 ml-3 text-sm font-semibold',
|
||||
'text-ink mb-2 ml-2 text-sm font-bold',
|
||||
section.title === 'Client' ? 'mt-2' : 'mt-5'
|
||||
)}
|
||||
>
|
||||
|
@ -129,14 +129,15 @@ export default function SettingsScreen({ navigation }: SettingsStackScreenProps<
|
|||
<SettingsItem
|
||||
title={item.title}
|
||||
leftIcon={item.icon}
|
||||
onPress={() => navigation.navigate(item.navigateTo)}
|
||||
onPress={() => navigation.navigate(item.navigateTo as any)}
|
||||
/>
|
||||
)}
|
||||
renderSectionHeader={renderSectionHeader}
|
||||
ListFooterComponent={
|
||||
<View style={tw`mt-6 mb-4 items-center`}>
|
||||
<Text style={tw`text-ink text-sm font-bold`}>Spacedrive</Text>
|
||||
<Text style={tw`text-ink-faint mt-0.5 text-xs`}>v0.1.0</Text>
|
||||
<Text style={tw`text-ink text-base font-bold`}>Spacedrive</Text>
|
||||
{/* TODO: Get this automatically (expo-device have this?) */}
|
||||
<Text style={tw`text-ink-faint mt-0.5 text-xs font-medium`}>v0.1.0</Text>
|
||||
</View>
|
||||
}
|
||||
showsVerticalScrollIndicator={false}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import React from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
import { useBridgeQuery } from '@sd/client';
|
||||
import { Input } from '~/components/form/Input';
|
||||
import Card from '~/components/layout/Card';
|
||||
import Divider from '~/components/primitive/Divider';
|
||||
import { Divider } from '~/components/primitive/Divider';
|
||||
import { SettingsInputTitle } from '~/components/settings/SettingsContainer';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
import { SettingsStackScreenProps } from '~/navigation/SettingsNavigator';
|
||||
|
||||
|
@ -14,7 +14,7 @@ const GeneralSettingsScreen = ({ navigation }: SettingsStackScreenProps<'General
|
|||
|
||||
return (
|
||||
<View style={tw`flex-1 p-4`}>
|
||||
<Card>
|
||||
<Card style={tw`bg-app-box`}>
|
||||
{/* Card Header */}
|
||||
<View style={tw`flex flex-row justify-between`}>
|
||||
<Text style={tw`text-ink font-semibold`}>Connected Node</Text>
|
||||
|
@ -32,9 +32,9 @@ const GeneralSettingsScreen = ({ navigation }: SettingsStackScreenProps<'General
|
|||
{/* Divider */}
|
||||
<Divider style={tw`mt-2 mb-4`} />
|
||||
{/* Node Name and Port */}
|
||||
<Text style={tw`text-ink-dull mb-1 ml-1 text-xs font-medium`}>Node Name</Text>
|
||||
<SettingsInputTitle>Node Name</SettingsInputTitle>
|
||||
<Input value={node.name} />
|
||||
<Text style={tw`text-ink-dull mt-2 mb-1 ml-1 text-xs font-medium`}>Node Port</Text>
|
||||
<SettingsInputTitle style={tw`mt-3`}>Node Port</SettingsInputTitle>
|
||||
<Input value={node.p2p_port?.toString() ?? '5795'} keyboardType="numeric" />
|
||||
</Card>
|
||||
</View>
|
||||
|
|
|
@ -31,13 +31,13 @@ function LibraryItem({
|
|||
<Animated.View
|
||||
style={[tw`flex flex-row items-center`, { transform: [{ translateX: translate }] }]}
|
||||
>
|
||||
<AnimatedButton size="md" onPress={() => navigation.replace('LibraryGeneralSettings')}>
|
||||
<AnimatedButton onPress={() => navigation.replace('LibraryGeneralSettings')}>
|
||||
<Pen size={18} color="white" />
|
||||
</AnimatedButton>
|
||||
<DeleteLibraryModal
|
||||
libraryUuid={library.uuid}
|
||||
trigger={
|
||||
<AnimatedButton size="md" style={tw`mx-2`}>
|
||||
<AnimatedButton style={tw`mx-2`}>
|
||||
<Trash size={18} color="white" />
|
||||
</AnimatedButton>
|
||||
}
|
||||
|
|
|
@ -0,0 +1,218 @@
|
|||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { Archive, ArrowsClockwise, Trash } from 'phosphor-react-native';
|
||||
import React from 'react';
|
||||
import { Controller } from 'react-hook-form';
|
||||
import { Alert, ScrollView, Text, View } from 'react-native';
|
||||
import { useLibraryMutation, useLibraryQuery } from '@sd/client';
|
||||
import { Input } from '~/components/form/Input';
|
||||
import { Switch } from '~/components/form/Switch';
|
||||
import DeleteLocationModal from '~/components/modal/confirm-modals/DeleteLocationModal';
|
||||
import { AnimatedButton, Button, FakeButton } from '~/components/primitive/Button';
|
||||
import { Divider } from '~/components/primitive/Divider';
|
||||
import {
|
||||
SettingsContainer,
|
||||
SettingsInputInfo,
|
||||
SettingsInputTitle
|
||||
} from '~/components/settings/SettingsContainer';
|
||||
import { SettingsItem } from '~/components/settings/SettingsItem';
|
||||
import { useZodForm, z } from '~/hooks/useZodForm';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
import { SettingsStackScreenProps } from '~/navigation/SettingsNavigator';
|
||||
|
||||
const schema = z.object({
|
||||
displayName: z.string(),
|
||||
localPath: z.string(),
|
||||
indexer_rules_ids: z.array(z.string()),
|
||||
generatePreviewMedia: z.boolean(),
|
||||
syncPreviewMedia: z.boolean(),
|
||||
hidden: z.boolean()
|
||||
});
|
||||
|
||||
const EditLocationSettingsScreen = ({
|
||||
route,
|
||||
navigation
|
||||
}: SettingsStackScreenProps<'EditLocationSettings'>) => {
|
||||
const { id } = route.params;
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const form = useZodForm({ schema });
|
||||
|
||||
const updateLocation = useLibraryMutation('locations.update', {
|
||||
onError: (e) => console.log({ e }),
|
||||
onSuccess: () => {
|
||||
form.reset(form.getValues());
|
||||
queryClient.invalidateQueries(['locations.list']);
|
||||
// TODO: Show toast & navigate back & reset input focus!
|
||||
}
|
||||
});
|
||||
|
||||
const onSubmit = form.handleSubmit((data) =>
|
||||
updateLocation.mutateAsync({
|
||||
id: Number(id),
|
||||
name: data.displayName,
|
||||
sync_preview_media: data.syncPreviewMedia,
|
||||
generate_preview_media: data.generatePreviewMedia,
|
||||
hidden: data.hidden,
|
||||
indexer_rules_ids: []
|
||||
})
|
||||
);
|
||||
|
||||
navigation.setOptions({
|
||||
headerRight: () => (
|
||||
<View style={tw`mr-1 flex flex-row gap-x-1`}>
|
||||
{form.formState.isDirty && (
|
||||
<AnimatedButton
|
||||
variant="outline"
|
||||
onPress={() => form.reset()}
|
||||
disabled={!form.formState.isDirty}
|
||||
>
|
||||
<Text style={tw`text-white`}>Reset</Text>
|
||||
</AnimatedButton>
|
||||
)}
|
||||
<AnimatedButton
|
||||
onPress={onSubmit}
|
||||
disabled={!form.formState.isDirty || form.formState.isSubmitting}
|
||||
variant={form.formState.isDirty ? 'accent' : 'outline'}
|
||||
>
|
||||
<Text style={tw`font-bold text-white`}>Save</Text>
|
||||
</AnimatedButton>
|
||||
</View>
|
||||
)
|
||||
});
|
||||
|
||||
useLibraryQuery(['locations.getById', id], {
|
||||
onSuccess: (data) => {
|
||||
if (data && !form.formState.isDirty)
|
||||
form.reset({
|
||||
displayName: data.name,
|
||||
localPath: data.path,
|
||||
indexer_rules_ids: data.indexer_rules.map((i) => i.indexer_rule.id.toString()),
|
||||
generatePreviewMedia: data.generate_preview_media,
|
||||
syncPreviewMedia: data.sync_preview_media,
|
||||
hidden: data.hidden
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const fullRescan = useLibraryMutation('locations.fullRescan');
|
||||
|
||||
return (
|
||||
<ScrollView contentContainerStyle={tw`gap-y-6 pb-12 pt-4`}>
|
||||
{/* Inputs */}
|
||||
<View style={tw`px-2`}>
|
||||
<SettingsInputTitle>Display Name</SettingsInputTitle>
|
||||
<Controller
|
||||
name="displayName"
|
||||
control={form.control}
|
||||
render={({ field: { onBlur, onChange, value } }) => (
|
||||
<Input onBlur={onBlur} onChangeText={onChange} value={value} />
|
||||
)}
|
||||
/>
|
||||
<SettingsInputInfo>
|
||||
The name of this Location, this is what will be displayed in the sidebar. Will not rename
|
||||
the actual folder on disk.
|
||||
</SettingsInputInfo>
|
||||
|
||||
<SettingsInputTitle style={tw`mt-3`}>Local Path</SettingsInputTitle>
|
||||
<Controller
|
||||
name="localPath"
|
||||
control={form.control}
|
||||
render={({ field: { onBlur, onChange, value } }) => (
|
||||
<Input onBlur={onBlur} onChangeText={onChange} value={value} />
|
||||
)}
|
||||
/>
|
||||
<SettingsInputInfo>
|
||||
The path to this Location, this is where the files will be stored on disk.
|
||||
</SettingsInputInfo>
|
||||
</View>
|
||||
<Divider style={tw`my-0`} />
|
||||
{/* Switches */}
|
||||
<View style={tw`gap-y-6`}>
|
||||
<SettingsContainer>
|
||||
<SettingsItem
|
||||
title="Generate preview media"
|
||||
rightArea={
|
||||
<Controller
|
||||
name="generatePreviewMedia"
|
||||
control={form.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Switch value={value} onValueChange={onChange} />
|
||||
)}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<SettingsItem
|
||||
title="Sync preview media with your devices"
|
||||
rightArea={
|
||||
<Controller
|
||||
name="syncPreviewMedia"
|
||||
control={form.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Switch value={value} onValueChange={onChange} />
|
||||
)}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<SettingsItem
|
||||
title="Hide location and contents from view"
|
||||
rightArea={
|
||||
<Controller
|
||||
name="hidden"
|
||||
control={form.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Switch value={value} onValueChange={onChange} />
|
||||
)}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</SettingsContainer>
|
||||
</View>
|
||||
{/* Indexer Rules */}
|
||||
<Text style={tw`text-center text-xs font-bold text-white`}>TODO: Indexer Rules</Text>
|
||||
{/* Buttons */}
|
||||
<View style={tw`gap-y-6`}>
|
||||
<SettingsContainer description="Perform a full rescan of this Location.">
|
||||
<SettingsItem
|
||||
title="Full Reindex"
|
||||
rightArea={
|
||||
<AnimatedButton size="sm" onPress={() => fullRescan.mutate(id)}>
|
||||
<ArrowsClockwise color="white" size={20} />
|
||||
</AnimatedButton>
|
||||
}
|
||||
/>
|
||||
</SettingsContainer>
|
||||
<SettingsContainer description="Extract data from Library as an archive, useful to preserve Location folder structure.">
|
||||
<SettingsItem
|
||||
title="Archive"
|
||||
rightArea={
|
||||
<AnimatedButton
|
||||
size="sm"
|
||||
onPress={() => Alert.alert('Archiving locations is coming soon...')}
|
||||
>
|
||||
<Archive color="white" size={20} />
|
||||
</AnimatedButton>
|
||||
}
|
||||
/>
|
||||
</SettingsContainer>
|
||||
<SettingsContainer description="This will not delete the actual folder on disk. Preview media will be...???">
|
||||
<SettingsItem
|
||||
title="Delete"
|
||||
rightArea={
|
||||
<DeleteLocationModal
|
||||
locationId={id}
|
||||
trigger={
|
||||
<FakeButton size="sm" variant="danger">
|
||||
<Trash color={tw.color('ink')} size={20} />
|
||||
</FakeButton>
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</SettingsContainer>
|
||||
</View>
|
||||
</ScrollView>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditLocationSettingsScreen;
|
|
@ -1,23 +1,29 @@
|
|||
import { Trash } from 'phosphor-react-native';
|
||||
import React from 'react';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import { Alert, Text, View } from 'react-native';
|
||||
import { Controller } from 'react-hook-form';
|
||||
import { Alert, View } from 'react-native';
|
||||
import { useBridgeMutation, useLibraryContext } from '@sd/client';
|
||||
import { Input } from '~/components/form/Input';
|
||||
import { Switch } from '~/components/form/Switch';
|
||||
import { Button } from '~/components/primitive/Button';
|
||||
import { SettingsContainer } from '~/components/settings/SettingsContainer';
|
||||
import DeleteLibraryModal from '~/components/modal/confirm-modals/DeleteLibraryModal';
|
||||
import { AnimatedButton } from '~/components/primitive/Button';
|
||||
import { Divider } from '~/components/primitive/Divider';
|
||||
import { SettingsContainer, SettingsInputTitle } from '~/components/settings/SettingsContainer';
|
||||
import { SettingsItem } from '~/components/settings/SettingsItem';
|
||||
import { useAutoForm } from '~/hooks/useAutoForm';
|
||||
import { useZodForm, z } from '~/hooks/useZodForm';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
import { SettingsStackScreenProps } from '~/navigation/SettingsNavigator';
|
||||
|
||||
const schema = z.object({ name: z.string(), description: z.string() });
|
||||
|
||||
const LibraryGeneralSettingsScreen = ({
|
||||
navigation
|
||||
}: SettingsStackScreenProps<'LibraryGeneralSettings'>) => {
|
||||
const { library } = useLibraryContext();
|
||||
|
||||
const form = useForm({
|
||||
const form = useZodForm({
|
||||
schema,
|
||||
defaultValues: { name: library.config.name, description: library.config.description }
|
||||
});
|
||||
|
||||
|
@ -25,15 +31,14 @@ const LibraryGeneralSettingsScreen = ({
|
|||
|
||||
useAutoForm(form, (value) => {
|
||||
editLibrary({ description: value.description, name: value.name, id: library.uuid });
|
||||
console.log('Updated', value);
|
||||
// console.log('Updated', value);
|
||||
// TODO: Show toast
|
||||
});
|
||||
|
||||
return (
|
||||
<View>
|
||||
{/* This looks bad... */}
|
||||
<View style={tw`bg-app-overlay mt-4 px-2 py-4`}>
|
||||
<Text style={tw`text-ink-dull mb-1 ml-1 text-xs font-medium`}>Name</Text>
|
||||
<View style={tw`gap-4`}>
|
||||
<View style={tw`mt-4 px-2`}>
|
||||
<SettingsInputTitle>Name</SettingsInputTitle>
|
||||
<Controller
|
||||
name="name"
|
||||
control={form.control}
|
||||
|
@ -42,7 +47,7 @@ const LibraryGeneralSettingsScreen = ({
|
|||
)}
|
||||
/>
|
||||
{/* Description */}
|
||||
<Text style={tw`text-ink-dull mb-1 ml-1 mt-3 text-xs font-medium`}>Description</Text>
|
||||
<SettingsInputTitle style={tw`mt-4`}>Description</SettingsInputTitle>
|
||||
<Controller
|
||||
name="description"
|
||||
control={form.control}
|
||||
|
@ -51,27 +56,31 @@ const LibraryGeneralSettingsScreen = ({
|
|||
)}
|
||||
/>
|
||||
</View>
|
||||
{/* Encrypt */}
|
||||
<View style={tw`mt-6`} />
|
||||
<SettingsContainer description="Enable encryption for this library, this will only encrypt the Spacedrive database, not the files themselves.">
|
||||
<SettingsItem title="Encrypt Library" rightArea={<Switch value={true} />} />
|
||||
</SettingsContainer>
|
||||
<View style={tw`mt-6`} />
|
||||
{/* Export */}
|
||||
<SettingsItem title="Export Library" onPress={() => Alert.alert('TODO')} />
|
||||
<View style={tw`mt-4`} />
|
||||
{/* Delete Library */}
|
||||
{/* TODO: Open delete library dialog here, but do handle library switching and what happens if there is no library set ? */}
|
||||
<SettingsContainer description="This is permanent, your files will not be deleted, only the Spacedrive library.">
|
||||
<SettingsItem
|
||||
title="Delete Library"
|
||||
rightArea={
|
||||
<Button size="sm" variant="danger" onPress={() => Alert.alert('TODO')}>
|
||||
<Trash color={tw.color('ink')} size={20} />
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</SettingsContainer>
|
||||
<Divider />
|
||||
<View style={tw`gap-y-6`}>
|
||||
{/* Encrypt */}
|
||||
<SettingsContainer description="Enable encryption for this library, this will only encrypt the Spacedrive database, not the files themselves.">
|
||||
<SettingsItem title="Encrypt Library" rightArea={<Switch value={true} />} />
|
||||
</SettingsContainer>
|
||||
{/* Export */}
|
||||
<SettingsItem title="Export Library" onPress={() => Alert.alert('TODO')} />
|
||||
{/* Delete Library */}
|
||||
<SettingsContainer description="This is permanent, your files will not be deleted, only the Spacedrive library.">
|
||||
<SettingsItem
|
||||
title="Delete Library"
|
||||
rightArea={
|
||||
<DeleteLibraryModal
|
||||
libraryUuid={library.uuid}
|
||||
trigger={
|
||||
<AnimatedButton size="sm" variant="danger">
|
||||
<Trash color={tw.color('ink')} size={20} />
|
||||
</AnimatedButton>
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</SettingsContainer>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { CaretRight, Repeat, Trash } from 'phosphor-react-native';
|
||||
import { CaretRight, Pen, Repeat, Trash } from 'phosphor-react-native';
|
||||
import { Animated, FlatList, Pressable, Text, View } from 'react-native';
|
||||
import { Swipeable } from 'react-native-gesture-handler';
|
||||
import {
|
||||
|
@ -14,7 +14,13 @@ import DeleteLocationModal from '~/components/modal/confirm-modals/DeleteLocatio
|
|||
import { tw, twStyle } from '~/lib/tailwind';
|
||||
import { SettingsStackScreenProps } from '~/navigation/SettingsNavigator';
|
||||
|
||||
function LocationItem({ location, index }: { location: Location & { node: Node }; index: number }) {
|
||||
type LocationItemProps = {
|
||||
location: Location & { node: Node };
|
||||
index: number;
|
||||
navigation: SettingsStackScreenProps<'LocationSettings'>['navigation'];
|
||||
};
|
||||
|
||||
function LocationItem({ location, index, navigation }: LocationItemProps) {
|
||||
const fullRescan = useLibraryMutation('locations.fullRescan', {
|
||||
onMutate: () => {
|
||||
// TODO: Show Toast
|
||||
|
@ -23,7 +29,11 @@ function LocationItem({ location, index }: { location: Location & { node: Node }
|
|||
|
||||
const onlineLocations = useOnlineLocations();
|
||||
|
||||
const renderRightActions = (progress: Animated.AnimatedInterpolation<number>) => {
|
||||
const renderRightActions = (
|
||||
progress: Animated.AnimatedInterpolation<number>,
|
||||
_: any,
|
||||
swipeable: Swipeable
|
||||
) => {
|
||||
const translate = progress.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [100, 0],
|
||||
|
@ -32,8 +42,20 @@ function LocationItem({ location, index }: { location: Location & { node: Node }
|
|||
|
||||
return (
|
||||
<Animated.View
|
||||
style={[tw`flex flex-row items-center`, { transform: [{ translateX: translate }] }]}
|
||||
style={[
|
||||
tw`mr-3 flex flex-row items-center gap-2`,
|
||||
{ transform: [{ translateX: translate }] }
|
||||
]}
|
||||
>
|
||||
<Pressable
|
||||
style={tw`border-app-line bg-app-button items-center justify-center rounded-md border py-1.5 px-3 shadow-sm`}
|
||||
onPress={() => {
|
||||
navigation.navigate('EditLocationSettings', { id: location.id });
|
||||
swipeable.close();
|
||||
}}
|
||||
>
|
||||
<Pen size={18} color="white" />
|
||||
</Pressable>
|
||||
<DeleteLocationModal
|
||||
locationId={location.id}
|
||||
trigger={
|
||||
|
@ -46,7 +68,7 @@ function LocationItem({ location, index }: { location: Location & { node: Node }
|
|||
/>
|
||||
{/* Full Re-scan IS too much here */}
|
||||
<Pressable
|
||||
style={tw`border-app-line bg-app-button mx-2 items-center justify-center rounded-md border py-1.5 px-3 shadow-sm`}
|
||||
style={tw`border-app-line bg-app-button items-center justify-center rounded-md border py-1.5 px-3 shadow-sm`}
|
||||
onPress={() => fullRescan.mutate(location.id)}
|
||||
>
|
||||
<Repeat size={18} color="white" />
|
||||
|
@ -106,7 +128,9 @@ const LocationSettingsScreen = ({ navigation }: SettingsStackScreenProps<'Locati
|
|||
<FlatList
|
||||
data={locations}
|
||||
keyExtractor={(item) => item.id.toString()}
|
||||
renderItem={({ item, index }) => <LocationItem location={item} index={index} />}
|
||||
renderItem={({ item, index }) => (
|
||||
<LocationItem navigation={navigation} location={item} index={index} />
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
|
|
@ -29,13 +29,13 @@ function TagItem({ tag, index }: { tag: Tag; index: number }) {
|
|||
style={[tw`flex flex-row items-center`, { transform: [{ translateX: translate }] }]}
|
||||
>
|
||||
<UpdateTagModal tag={tag} ref={updateTagModalRef} onSubmit={() => swipeable.close()} />
|
||||
<AnimatedButton size="md" onPress={() => updateTagModalRef.current?.present()}>
|
||||
<AnimatedButton onPress={() => updateTagModalRef.current?.present()}>
|
||||
<Pen size={18} color="white" />
|
||||
</AnimatedButton>
|
||||
<DeleteTagModal
|
||||
tagId={tag.id}
|
||||
trigger={
|
||||
<AnimatedButton size="md" style={tw`mx-2`}>
|
||||
<AnimatedButton style={tw`mx-2`}>
|
||||
<Trash size={18} color="white" />
|
||||
</AnimatedButton>
|
||||
}
|
||||
|
|
|
@ -36,6 +36,8 @@ module.exports = {
|
|||
button: 'hsla(230, 15%, 23%, 1)',
|
||||
// menu
|
||||
menu: 'hsla(230, 25%, 5%, 1)',
|
||||
// input
|
||||
input: 'hsla(230, 15%, 20%, 1)',
|
||||
50: 'hsla(230, 15%, 5%, 1)',
|
||||
100: 'hsla(230, 15%, 10%, 1)',
|
||||
150: 'hsla(230, 15%, 15%, 1)',
|
||||
|
|
|
@ -112,8 +112,8 @@ impl Node {
|
|||
);
|
||||
#[cfg(not(target_os = "android"))]
|
||||
let subscriber = subscriber.with(tracing_subscriber::fmt::layer().with_filter(CONSOLE_LOG_FILTER));
|
||||
#[cfg(target_os = "android")]
|
||||
let subscriber = subscriber.with(tracing_android::layer("com.spacedrive.app").unwrap()); // TODO: This is not working
|
||||
// #[cfg(target_os = "android")]
|
||||
// let subscriber = subscriber.with(tracing_android::layer("com.spacedrive.app").unwrap()); // TODO: This is not working
|
||||
subscriber
|
||||
// .with(
|
||||
// Layer::default()
|
||||
|
|
|
@ -59,7 +59,7 @@ To run mobile app
|
|||
1. Install [Android Studio](https://developer.android.com/studio) for Android and [Xcode](https://apps.apple.com/au/app/xcode/id497799835) for IOS development
|
||||
2. `./.github/scripts/setup-system.sh mobile`
|
||||
_The should setup most of the dependencies for the mobile app to build._
|
||||
3. You must also ensure you have [NDK 24.0.8215888 and CMake](https://developer.android.com/studio/projects/install-ndk#default-version) in Android Studio
|
||||
3. You must also ensure you have [NDK 23.1.7779620 and CMake](https://developer.android.com/studio/projects/install-ndk#default-version) in Android Studio
|
||||
4. `pnpm mobile android` - runs on Android Emulator
|
||||
5. `pnpm mobile ios` - runs on iOS Emulator
|
||||
|
||||
|
@ -68,4 +68,4 @@ To run mobile app
|
|||
If you are having issues ensure you are using the following versions of Rust and Node:
|
||||
|
||||
- Rust version: **1.67.0**
|
||||
- Node version: **17**
|
||||
- Node version: **18**
|
||||
|
|
|
@ -1,14 +1,9 @@
|
|||
import { Eye, EyeSlash, Info } from 'phosphor-react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import {
|
||||
Algorithm,
|
||||
HASHING_ALGOS,
|
||||
HashingAlgoSlug,
|
||||
generatePassword,
|
||||
useLibraryMutation
|
||||
} from '@sd/client';
|
||||
import { Algorithm, HASHING_ALGOS, HashingAlgoSlug, useLibraryMutation } from '@sd/client';
|
||||
import { Button, CategoryHeading, Input, Select, SelectOption, Slider, Switch, tw } from '@sd/ui';
|
||||
import { Tooltip } from '@sd/ui';
|
||||
import { generatePassword } from '~/util';
|
||||
|
||||
const KeyHeading = tw(CategoryHeading)`mb-1`;
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { useForm } from 'react-hook-form';
|
||||
import { useBridgeMutation, useLibraryContext } from '@sd/client';
|
||||
import { Button, Input, Switch } from '@sd/ui';
|
||||
import { Button, Input, Switch, dialogManager } from '@sd/ui';
|
||||
import { useDebouncedFormWatch } from '~/hooks/useDebouncedForm';
|
||||
import { Heading } from '../Layout';
|
||||
import Setting from '../Setting';
|
||||
import DeleteLibraryDialog from '../node/libraries/DeleteDialog';
|
||||
|
||||
export const Component = () => {
|
||||
const { library } = useLibraryContext();
|
||||
|
@ -64,7 +65,16 @@ export const Component = () => {
|
|||
description="This is permanent, your files will not be deleted, only the Spacedrive library."
|
||||
>
|
||||
<div className="mt-2">
|
||||
<Button size="sm" variant="colored" className="border-red-500 bg-red-500">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="colored"
|
||||
className="border-red-500 bg-red-500"
|
||||
onClick={() => {
|
||||
dialogManager.create((dp) => (
|
||||
<DeleteLibraryDialog {...dp} libraryUuid={library.uuid} />
|
||||
));
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
@ -4,22 +4,14 @@ import {
|
|||
Algorithm,
|
||||
HASHING_ALGOS,
|
||||
HashingAlgoSlug,
|
||||
generatePassword,
|
||||
hashingAlgoSlugSchema,
|
||||
useLibraryMutation
|
||||
} from '@sd/client';
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
Input,
|
||||
PasswordMeter,
|
||||
Select,
|
||||
SelectOption,
|
||||
UseDialogProps,
|
||||
useDialog
|
||||
} from '@sd/ui';
|
||||
import { Button, Dialog, Input, Select, SelectOption, UseDialogProps, useDialog } from '@sd/ui';
|
||||
import { useZodForm, z } from '@sd/ui/src/forms';
|
||||
import { showAlertDialog } from '~/components/AlertDialog';
|
||||
import { PasswordMeter } from '~/components/PasswordMeter';
|
||||
import { generatePassword } from '~/util';
|
||||
|
||||
const schema = z.object({
|
||||
masterPassword: z.string(),
|
||||
|
|
|
@ -5,7 +5,6 @@ import {
|
|||
Algorithm,
|
||||
HASHING_ALGOS,
|
||||
HashingAlgoSlug,
|
||||
generatePassword,
|
||||
hashingAlgoSlugSchema,
|
||||
useBridgeMutation,
|
||||
usePlausibleEvent
|
||||
|
@ -14,7 +13,6 @@ import {
|
|||
Button,
|
||||
CheckBox,
|
||||
Dialog,
|
||||
PasswordMeter,
|
||||
Select,
|
||||
SelectOption,
|
||||
Tooltip,
|
||||
|
@ -22,6 +20,8 @@ import {
|
|||
useDialog
|
||||
} from '@sd/ui';
|
||||
import { forms } from '@sd/ui';
|
||||
import { PasswordMeter } from '~/components/PasswordMeter';
|
||||
import { generatePassword } from '~/util';
|
||||
import { usePlatform } from '~/util/Platform';
|
||||
|
||||
const { Input, z, useZodForm } = forms;
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useNavigate } from 'react-router';
|
||||
import {
|
||||
Algorithm,
|
||||
HASHING_ALGOS,
|
||||
resetOnboardingStore,
|
||||
telemetryStore,
|
||||
|
@ -59,7 +57,7 @@ export default function OnboardingCreatingLibrary() {
|
|||
type: 'TokenizedPassword',
|
||||
value: obStore.passwordSetToken || ''
|
||||
},
|
||||
algorithm: obStore.algorithm as Algorithm,
|
||||
algorithm: obStore.algorithm,
|
||||
hashing_algorithm: HASHING_ALGOS[obStore.hashingAlgorithm]
|
||||
});
|
||||
|
||||
|
@ -84,6 +82,7 @@ export default function OnboardingCreatingLibrary() {
|
|||
clearTimeout(timer);
|
||||
clearTimeout(timer2);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { useState } from 'react';
|
||||
import { useNavigate } from 'react-router';
|
||||
import { getOnboardingStore, useBridgeMutation, useOnboardingStore } from '@sd/client';
|
||||
import { Button, Card, PasswordMeter } from '@sd/ui';
|
||||
import { Button, Card } from '@sd/ui';
|
||||
import { Form, PasswordInput, useZodForm, z } from '@sd/ui/src/forms';
|
||||
import { PasswordMeter } from '~/components/PasswordMeter';
|
||||
import { OnboardingContainer, OnboardingDescription, OnboardingTitle } from './Layout';
|
||||
import { useUnlockOnboardingScreen } from './Progress';
|
||||
|
||||
|
@ -118,7 +119,9 @@ export default function OnboardingNewLibrary() {
|
|||
disabled={form.formState.isSubmitting}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
onClick={(event: any) => {
|
||||
// Without this, form is submitted before token gets removed
|
||||
event.preventDefault();
|
||||
getOnboardingStore().passwordSetToken = null;
|
||||
form.reset();
|
||||
}}
|
||||
|
|
45
interface/components/PasswordMeter.tsx
Normal file
45
interface/components/PasswordMeter.tsx
Normal file
|
@ -0,0 +1,45 @@
|
|||
import clsx from 'clsx';
|
||||
import { getPasswordStrength } from '@sd/client';
|
||||
|
||||
export interface PasswordMeterProps {
|
||||
password: string;
|
||||
}
|
||||
|
||||
export const PasswordMeter = (props: PasswordMeterProps) => {
|
||||
const { score, scoreText } = getPasswordStrength(props.password);
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<h3 className="text-sm">Password strength</h3>
|
||||
<span
|
||||
className={clsx(
|
||||
'absolute top-0.5 right-0 px-1 text-sm font-semibold',
|
||||
score === 0 && 'text-red-500',
|
||||
score === 1 && 'text-red-500',
|
||||
score === 2 && 'text-amber-400',
|
||||
score === 3 && 'text-lime-500',
|
||||
score === 4 && 'text-accent'
|
||||
)}
|
||||
>
|
||||
{scoreText}
|
||||
</span>
|
||||
<div className="flex grow">
|
||||
<div className="bg-app-box/50 mt-2 w-full rounded-full">
|
||||
<div
|
||||
style={{
|
||||
width: `${score !== 0 ? score * 25 : 12.5}%`
|
||||
}}
|
||||
className={clsx(
|
||||
'h-2 rounded-full',
|
||||
score === 0 && 'bg-red-500',
|
||||
score === 1 && 'bg-red-500',
|
||||
score === 2 && 'bg-amber-400',
|
||||
score === 3 && 'bg-lime-500',
|
||||
score === 4 && 'bg-accent'
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -19,6 +19,7 @@
|
|||
"@fontsource/inter": "^4.5.13",
|
||||
"@headlessui/react": "^1.7.3",
|
||||
"@hookform/resolvers": "^2.9.10",
|
||||
"crypto-random-string": "^5.0.0",
|
||||
"@radix-ui/react-progress": "^1.0.1",
|
||||
"@radix-ui/react-slider": "^1.1.0",
|
||||
"@radix-ui/react-toast": "^1.1.2",
|
||||
|
@ -35,9 +36,6 @@
|
|||
"@tanstack/react-query-devtools": "^4.22.0",
|
||||
"@tanstack/react-virtual": "3.0.0-beta.18",
|
||||
"@vitejs/plugin-react": "^2.1.0",
|
||||
"@zxcvbn-ts/core": "^2.1.0",
|
||||
"@zxcvbn-ts/language-common": "^2.0.1",
|
||||
"@zxcvbn-ts/language-en": "^2.1.0",
|
||||
"autoprefixer": "^10.4.12",
|
||||
"byte-size": "^8.1.0",
|
||||
"class-variance-authority": "^0.4.0",
|
||||
|
@ -48,7 +46,7 @@
|
|||
"react-colorful": "^5.6.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-error-boundary": "^3.1.4",
|
||||
"react-hook-form": "^7.36.1",
|
||||
"react-hook-form": "^7.43.5",
|
||||
"react-json-view": "^1.21.3",
|
||||
"react-loading-skeleton": "^3.1.0",
|
||||
"react-qr-code": "^2.0.11",
|
||||
|
|
5
interface/util/index.tsx
Normal file
5
interface/util/index.tsx
Normal file
|
@ -0,0 +1,5 @@
|
|||
import cryptoRandomString from 'crypto-random-string';
|
||||
|
||||
// NOTE: `crypto` module is not available in RN so this can't be in client
|
||||
export const generatePassword = (length: number) =>
|
||||
cryptoRandomString({ length, type: 'ascii-printable' });
|
|
@ -21,7 +21,7 @@
|
|||
"codegen": "cargo test -p sd-core api::tests::test_and_export_rspc_bindings -- --exact",
|
||||
"typecheck": "turbo run typecheck",
|
||||
"lint": "turbo run lint",
|
||||
"lint:fix": "turbo run lint -- lint:fix",
|
||||
"lint:fix": "turbo run lint -- --fix",
|
||||
"clean": "rimraf node_modules/ **/node_modules/ target/ **/.build/ **/.next/ **/dist/**"
|
||||
},
|
||||
"pnpm": {
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
"@rspc/react": "^0.0.0-main-7c0a67c1",
|
||||
"@sd/config": "workspace:*",
|
||||
"@tanstack/react-query": "^4.12.0",
|
||||
"crypto-random-string": "^5.0.0",
|
||||
"@zxcvbn-ts/core": "^2.1.0",
|
||||
"@zxcvbn-ts/language-common": "^2.0.1",
|
||||
"@zxcvbn-ts/language-en": "^2.1.0",
|
||||
"plausible-tracker": "^0.3.8",
|
||||
"valtio": "^1.7.4"
|
||||
},
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue