Rustify mobile (#361)

* Refactor navigation flow & types

* Remove drawer screen wrapper

* Remove DrawerItem + cleanup

* Switch to JS Stack Nav & header animations

* [WIP] Spacedrive core on Android & IOS

* Update Podfile and cleanup Contributing guide.

* Remove @sd/core from mobile

* File Modal

* Prettify File Modal & Add date-fns

* IOS subscriptions

* Update package versions

* Custom header for stack screens

* android subscriptions

* Animate Drawer button & template for Search screen

* Search header

* Fix Search icon being weird

* Merge branch 'main' into rustify-mobile

* fix rspc dep + setup script for mobile

* Less margin on header

* Move shared assets & drawer logo for mobile

* support for IOS simulator

* add type safe rspc hooks to mobile

* Cleanup PR & Update packages

* Updated bindings from main

* Update lefthook.yml

* Remove `tag` folder from core
The `tag` folder came back from the dead. Maybe it got confused in merge conflict?

* update pnpm lockfile + fix tsc errors

* fix asset import

Co-authored-by: Utku Bakir <74243531+utkubakir@users.noreply.github.com>
This commit is contained in:
Oscar Beaumont 2022-08-29 19:59:09 +08:00 committed by GitHub
parent 8be083c062
commit c7441d1d64
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
93 changed files with 3093 additions and 1709 deletions

View file

@ -37,39 +37,43 @@ This project uses [Cargo](https://doc.rust-lang.org/cargo/getting-started/instal
> Note: MacOS M1 users should choose the customize option in the rustup init script and enter `x86_64-apple-darwin` as the default host triple instead of the default `aarch64-apple-darwin`
- `$ git clone https://github.com/spacedriveapp/spacedrive`
- `$ cd spacedrive`
- `git clone https://github.com/spacedriveapp/spacedrive`
- `cd spacedrive`
- For Linux or MacOS users run: `./.github/scripts/setup-system.sh`
- This will install FFMPEG and any other required dependencies for Spacedrive to build.
- For Windows users run using PowerShell: `.\.github\scripts\setup-system.ps1`
- This will install pnpm, LLVM, FFMPEG and any other required dependencies for Spacedrive to build.
- Ensure you run it like documented above as it expects it is executed from the root of the repository.
- `$ pnpm i`
- `$ pnpm prep` - Runs all necessary codegen & builds required dependencies.
- `pnpm i`
- `pnpm prep` - Runs all necessary codegen & builds required dependencies.
To quickly run only the desktop app after `prep` you can use:
- `$ pnpm desktop dev`
- `pnpm desktop dev`
To run the landing page
- `$ pnpm web dev` - runs the web app for the embed
- `$ pnpm landing dev`
To run mobile app
- `$ cd apps/mobile && pnpm i` - As this is a seperated workspace, you need to do this!
- `$ pnpm android` - runs on Android Emulator
- `$ pnpm ios` - runs on iOS Emulator
- `$ pnpm dev` - For already bundled app
You also need `expo-cli` installed globally.
- `pnpm web dev` - runs the web app for the embed
- `pnpm landing dev`
If you are having issues ensure you are using the following versions of Rust and Node:
- Rust version: **1.62.0**
- Rust version: **1.63.0**
- Node version: **17**
##### Mobile app
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!
- `pnpm android` - runs on Android Emulator
- `pnpm ios` - runs on iOS Emulator
- `pnpm dev` - For already bundled app - This is only temporarily supported. The final app will require the Spacedrive Rust code which isn't included in Expo Go.
### Pull Request
When you're finished with the changes, create a pull request, also known as a PR.

430
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,13 @@
[workspace]
members = [
"apps/desktop/src-tauri",
"core",
"core/prisma",
"core/derive",
"apps/server",
]
resolver = "2"
members = [
"apps/desktop/src-tauri",
"apps/mobile/rust",
"core",
"core/prisma",
"apps/server"
]
[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" }

View file

@ -11,6 +11,7 @@ build = "build.rs"
[dependencies]
tauri = { version = "1.0.4", features = ["api-all", "macos-private-api"] }
rspc = { version = "0.0.4", features = ["tauri"] }
sdcore = { path = "../../../core" }
tokio = { version = "1.17.0", features = ["sync"] }
window-shadows = "0.1.2"

View file

@ -23,7 +23,7 @@ async fn main() {
let (node, router) = Node::new(data_dir).await;
let app = tauri::Builder::default()
.plugin(sdcore::rspc::integrations::tauri::plugin(router, {
.plugin(rspc::integrations::tauri::plugin(router, {
let node = node.clone();
move || node.get_request_context()
}))

View file

@ -14,6 +14,7 @@
"@icons-pack/react-simple-icons": "^5.2.0",
"@sd/interface": "link:../../packages/interface",
"@sd/ui": "link:../../packages/ui",
"@sd/assets": "link:../../packages/assets",
"@tryghost/content-api": "^1.11.0",
"@types/compression": "^1.7.2",
"@types/express": "^4.17.13",

View file

@ -6,10 +6,9 @@ import {
Twitch,
Twitter
} from '@icons-pack/react-simple-icons';
import AppLogo from '@sd/assets/images/logo.png';
import React from 'react';
import AppLogo from '../assets/images/logo.png';
function FooterLink(props: { children: string | JSX.Element; link: string; blank?: boolean }) {
return (
<a

View file

@ -1,11 +1,11 @@
import { BookOpenIcon, MapIcon, QuestionMarkCircleIcon, UsersIcon } from '@heroicons/react/solid';
import { Discord, Github } from '@icons-pack/react-simple-icons';
import AppLogo from '@sd/assets/images/logo.png';
import { Dropdown, DropdownItem } from '@sd/ui';
import clsx from 'clsx';
import { List } from 'phosphor-react';
import React, { useEffect, useState } from 'react';
import AppLogo from '../assets/images/logo.png';
import { positions } from '../pages/careers.page';
import { getWindow } from '../utils';

View file

@ -1 +1,3 @@
Make sure to run `pnpm i` in this folder after making changes to the `packages`.
- Note: If you add/remove something from `packages/assets` folder, you need to delete node_modules and run `pnpm i` again to link it.

View file

@ -3,6 +3,24 @@ apply plugin: "com.android.application"
import com.android.build.OutputFile
import org.apache.tools.ant.taskdefs.condition.Os
apply plugin: 'org.mozilla.rust-android-gradle.rust-android'
cargo {
module = "../../rust"
libname = "sdcore"
// profile = 'release',
pythonCommand = 'python3'
targets = ["arm", "arm64", "x86", "x86_64"]
targetDirectory = "../.././../../target" // Monorepo moment
}
tasks.whenTaskAdded { task ->
if ((task.name == 'javaPreCompileDebug' || task.name == 'javaPreCompileRelease')) {
task.dependsOn 'cargoBuild'
}
}
/**
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
* and bundleReleaseJsAndAssets).

View file

@ -34,7 +34,7 @@ public class MainApplication extends Application implements ReactApplication {
@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 MyReactNativePackage());
packages.add(new com.spacedrive.app.SpacedrivePackage());
return packages;
}

View file

@ -0,0 +1,76 @@
package com.spacedrive.app;
import android.content.Context;
import android.os.Build;
import androidx.annotation.RequiresApi;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import javax.annotation.Nullable;
public class SDCore extends ReactContextBaseJavaModule {
SDCore(ReactApplicationContext context) { super(context); }
private boolean registeredWithRust = false;
private int listeners = 0;
@Override
public String getName()
{
return "SDCore";
}
static {
System.loadLibrary("sdcore");
}
// is exposed by Rust and is used to register the subscription
private native void registerCoreEventListener();
private native void handleCoreMsg(String query, Promise promise);
@ReactMethod
public void sd_core_msg(String query, Promise promise)
{
this.handleCoreMsg(query, promise);
}
public String getDataDirectory()
{
return getCurrentActivity().getFilesDir().toString();
}
@ReactMethod
public void addListener(String eventName)
{
if (!registeredWithRust)
{
this.registerCoreEventListener();
}
this.listeners++;
}
@ReactMethod
public void removeListeners(Integer count)
{
this.listeners--;
}
public void sendCoreEvent(String body)
{
if (this.listeners > 0)
{
this.getReactApplicationContext()
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("SDCoreEvent", body);
}
}
}

View file

@ -0,0 +1,28 @@
package com.spacedrive.app;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class SpacedrivePackage implements ReactPackage {
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new SDCore(reactContext));
return modules;
}
}

View file

@ -24,11 +24,15 @@ buildscript {
repositories {
google()
mavenCentral()
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath('com.android.tools.build:gradle:7.1.1')
classpath('com.facebook.react:react-native-gradle-plugin')
classpath('de.undercouch:gradle-download-task:5.0.1')
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
}

View file

@ -9,27 +9,27 @@ PODS:
- ExpoModulesCore
- EXFont (10.2.0):
- ExpoModulesCore
- Expo (46.0.2):
- Expo (46.0.9):
- ExpoModulesCore
- ExpoKeepAwake (10.2.0):
- ExpoModulesCore
- ExpoModulesCore (0.11.3):
- ExpoModulesCore (0.11.4):
- React-Core
- ReactCommon/turbomodule/core
- EXSplashScreen (0.16.1):
- EXSplashScreen (0.16.2):
- ExpoModulesCore
- React-Core
- FBLazyVector (0.69.3)
- FBReactNativeSpec (0.69.3):
- FBLazyVector (0.69.4)
- FBReactNativeSpec (0.69.4):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTRequired (= 0.69.3)
- RCTTypeSafety (= 0.69.3)
- React-Core (= 0.69.3)
- React-jsi (= 0.69.3)
- ReactCommon/turbomodule/core (= 0.69.3)
- RCTRequired (= 0.69.4)
- RCTTypeSafety (= 0.69.4)
- React-Core (= 0.69.4)
- React-jsi (= 0.69.4)
- ReactCommon/turbomodule/core (= 0.69.4)
- fmt (6.2.1)
- glog (0.3.5)
- hermes-engine (0.69.3)
- hermes-engine (0.69.4)
- libevent (2.1.12)
- RCT-Folly (2021.06.28.00-v2):
- boost
@ -48,214 +48,214 @@ PODS:
- fmt (~> 6.2.1)
- glog
- libevent
- RCTRequired (0.69.3)
- RCTTypeSafety (0.69.3):
- FBLazyVector (= 0.69.3)
- RCTRequired (= 0.69.3)
- React-Core (= 0.69.3)
- React (0.69.3):
- React-Core (= 0.69.3)
- React-Core/DevSupport (= 0.69.3)
- React-Core/RCTWebSocket (= 0.69.3)
- React-RCTActionSheet (= 0.69.3)
- React-RCTAnimation (= 0.69.3)
- React-RCTBlob (= 0.69.3)
- React-RCTImage (= 0.69.3)
- React-RCTLinking (= 0.69.3)
- React-RCTNetwork (= 0.69.3)
- React-RCTSettings (= 0.69.3)
- React-RCTText (= 0.69.3)
- React-RCTVibration (= 0.69.3)
- React-bridging (0.69.3):
- RCTRequired (0.69.4)
- RCTTypeSafety (0.69.4):
- FBLazyVector (= 0.69.4)
- RCTRequired (= 0.69.4)
- React-Core (= 0.69.4)
- React (0.69.4):
- React-Core (= 0.69.4)
- React-Core/DevSupport (= 0.69.4)
- React-Core/RCTWebSocket (= 0.69.4)
- React-RCTActionSheet (= 0.69.4)
- React-RCTAnimation (= 0.69.4)
- React-RCTBlob (= 0.69.4)
- React-RCTImage (= 0.69.4)
- React-RCTLinking (= 0.69.4)
- React-RCTNetwork (= 0.69.4)
- React-RCTSettings (= 0.69.4)
- React-RCTText (= 0.69.4)
- React-RCTVibration (= 0.69.4)
- React-bridging (0.69.4):
- RCT-Folly (= 2021.06.28.00-v2)
- React-jsi (= 0.69.3)
- React-callinvoker (0.69.3)
- React-Codegen (0.69.3):
- FBReactNativeSpec (= 0.69.3)
- React-jsi (= 0.69.4)
- React-callinvoker (0.69.4)
- React-Codegen (0.69.4):
- FBReactNativeSpec (= 0.69.4)
- RCT-Folly (= 2021.06.28.00-v2)
- RCTRequired (= 0.69.3)
- RCTTypeSafety (= 0.69.3)
- React-Core (= 0.69.3)
- React-jsi (= 0.69.3)
- React-jsiexecutor (= 0.69.3)
- ReactCommon/turbomodule/core (= 0.69.3)
- React-Core (0.69.3):
- RCTRequired (= 0.69.4)
- RCTTypeSafety (= 0.69.4)
- React-Core (= 0.69.4)
- React-jsi (= 0.69.4)
- React-jsiexecutor (= 0.69.4)
- ReactCommon/turbomodule/core (= 0.69.4)
- React-Core (0.69.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default (= 0.69.3)
- React-cxxreact (= 0.69.3)
- React-jsi (= 0.69.3)
- React-jsiexecutor (= 0.69.3)
- React-perflogger (= 0.69.3)
- React-Core/Default (= 0.69.4)
- React-cxxreact (= 0.69.4)
- React-jsi (= 0.69.4)
- React-jsiexecutor (= 0.69.4)
- React-perflogger (= 0.69.4)
- Yoga
- React-Core/CoreModulesHeaders (0.69.3):
- React-Core/CoreModulesHeaders (0.69.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.69.3)
- React-jsi (= 0.69.3)
- React-jsiexecutor (= 0.69.3)
- React-perflogger (= 0.69.3)
- React-cxxreact (= 0.69.4)
- React-jsi (= 0.69.4)
- React-jsiexecutor (= 0.69.4)
- React-perflogger (= 0.69.4)
- Yoga
- React-Core/Default (0.69.3):
- React-Core/Default (0.69.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-cxxreact (= 0.69.3)
- React-jsi (= 0.69.3)
- React-jsiexecutor (= 0.69.3)
- React-perflogger (= 0.69.3)
- React-cxxreact (= 0.69.4)
- React-jsi (= 0.69.4)
- React-jsiexecutor (= 0.69.4)
- React-perflogger (= 0.69.4)
- Yoga
- React-Core/DevSupport (0.69.3):
- React-Core/DevSupport (0.69.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default (= 0.69.3)
- React-Core/RCTWebSocket (= 0.69.3)
- React-cxxreact (= 0.69.3)
- React-jsi (= 0.69.3)
- React-jsiexecutor (= 0.69.3)
- React-jsinspector (= 0.69.3)
- React-perflogger (= 0.69.3)
- React-Core/Default (= 0.69.4)
- React-Core/RCTWebSocket (= 0.69.4)
- React-cxxreact (= 0.69.4)
- React-jsi (= 0.69.4)
- React-jsiexecutor (= 0.69.4)
- React-jsinspector (= 0.69.4)
- React-perflogger (= 0.69.4)
- Yoga
- React-Core/RCTActionSheetHeaders (0.69.3):
- React-Core/RCTActionSheetHeaders (0.69.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.69.3)
- React-jsi (= 0.69.3)
- React-jsiexecutor (= 0.69.3)
- React-perflogger (= 0.69.3)
- React-cxxreact (= 0.69.4)
- React-jsi (= 0.69.4)
- React-jsiexecutor (= 0.69.4)
- React-perflogger (= 0.69.4)
- Yoga
- React-Core/RCTAnimationHeaders (0.69.3):
- React-Core/RCTAnimationHeaders (0.69.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.69.3)
- React-jsi (= 0.69.3)
- React-jsiexecutor (= 0.69.3)
- React-perflogger (= 0.69.3)
- React-cxxreact (= 0.69.4)
- React-jsi (= 0.69.4)
- React-jsiexecutor (= 0.69.4)
- React-perflogger (= 0.69.4)
- Yoga
- React-Core/RCTBlobHeaders (0.69.3):
- React-Core/RCTBlobHeaders (0.69.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.69.3)
- React-jsi (= 0.69.3)
- React-jsiexecutor (= 0.69.3)
- React-perflogger (= 0.69.3)
- React-cxxreact (= 0.69.4)
- React-jsi (= 0.69.4)
- React-jsiexecutor (= 0.69.4)
- React-perflogger (= 0.69.4)
- Yoga
- React-Core/RCTImageHeaders (0.69.3):
- React-Core/RCTImageHeaders (0.69.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.69.3)
- React-jsi (= 0.69.3)
- React-jsiexecutor (= 0.69.3)
- React-perflogger (= 0.69.3)
- React-cxxreact (= 0.69.4)
- React-jsi (= 0.69.4)
- React-jsiexecutor (= 0.69.4)
- React-perflogger (= 0.69.4)
- Yoga
- React-Core/RCTLinkingHeaders (0.69.3):
- React-Core/RCTLinkingHeaders (0.69.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.69.3)
- React-jsi (= 0.69.3)
- React-jsiexecutor (= 0.69.3)
- React-perflogger (= 0.69.3)
- React-cxxreact (= 0.69.4)
- React-jsi (= 0.69.4)
- React-jsiexecutor (= 0.69.4)
- React-perflogger (= 0.69.4)
- Yoga
- React-Core/RCTNetworkHeaders (0.69.3):
- React-Core/RCTNetworkHeaders (0.69.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.69.3)
- React-jsi (= 0.69.3)
- React-jsiexecutor (= 0.69.3)
- React-perflogger (= 0.69.3)
- React-cxxreact (= 0.69.4)
- React-jsi (= 0.69.4)
- React-jsiexecutor (= 0.69.4)
- React-perflogger (= 0.69.4)
- Yoga
- React-Core/RCTSettingsHeaders (0.69.3):
- React-Core/RCTSettingsHeaders (0.69.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.69.3)
- React-jsi (= 0.69.3)
- React-jsiexecutor (= 0.69.3)
- React-perflogger (= 0.69.3)
- React-cxxreact (= 0.69.4)
- React-jsi (= 0.69.4)
- React-jsiexecutor (= 0.69.4)
- React-perflogger (= 0.69.4)
- Yoga
- React-Core/RCTTextHeaders (0.69.3):
- React-Core/RCTTextHeaders (0.69.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.69.3)
- React-jsi (= 0.69.3)
- React-jsiexecutor (= 0.69.3)
- React-perflogger (= 0.69.3)
- React-cxxreact (= 0.69.4)
- React-jsi (= 0.69.4)
- React-jsiexecutor (= 0.69.4)
- React-perflogger (= 0.69.4)
- Yoga
- React-Core/RCTVibrationHeaders (0.69.3):
- React-Core/RCTVibrationHeaders (0.69.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.69.3)
- React-jsi (= 0.69.3)
- React-jsiexecutor (= 0.69.3)
- React-perflogger (= 0.69.3)
- React-cxxreact (= 0.69.4)
- React-jsi (= 0.69.4)
- React-jsiexecutor (= 0.69.4)
- React-perflogger (= 0.69.4)
- Yoga
- React-Core/RCTWebSocket (0.69.3):
- React-Core/RCTWebSocket (0.69.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default (= 0.69.3)
- React-cxxreact (= 0.69.3)
- React-jsi (= 0.69.3)
- React-jsiexecutor (= 0.69.3)
- React-perflogger (= 0.69.3)
- React-Core/Default (= 0.69.4)
- React-cxxreact (= 0.69.4)
- React-jsi (= 0.69.4)
- React-jsiexecutor (= 0.69.4)
- React-perflogger (= 0.69.4)
- Yoga
- React-CoreModules (0.69.3):
- React-CoreModules (0.69.4):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.69.3)
- React-Codegen (= 0.69.3)
- React-Core/CoreModulesHeaders (= 0.69.3)
- React-jsi (= 0.69.3)
- React-RCTImage (= 0.69.3)
- ReactCommon/turbomodule/core (= 0.69.3)
- React-cxxreact (0.69.3):
- RCTTypeSafety (= 0.69.4)
- React-Codegen (= 0.69.4)
- React-Core/CoreModulesHeaders (= 0.69.4)
- React-jsi (= 0.69.4)
- React-RCTImage (= 0.69.4)
- ReactCommon/turbomodule/core (= 0.69.4)
- React-cxxreact (0.69.4):
- boost (= 1.76.0)
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-callinvoker (= 0.69.3)
- React-jsi (= 0.69.3)
- React-jsinspector (= 0.69.3)
- React-logger (= 0.69.3)
- React-perflogger (= 0.69.3)
- React-runtimeexecutor (= 0.69.3)
- React-hermes (0.69.3):
- React-callinvoker (= 0.69.4)
- React-jsi (= 0.69.4)
- React-jsinspector (= 0.69.4)
- React-logger (= 0.69.4)
- React-perflogger (= 0.69.4)
- React-runtimeexecutor (= 0.69.4)
- React-hermes (0.69.4):
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2021.06.28.00-v2)
- RCT-Folly/Futures (= 2021.06.28.00-v2)
- React-cxxreact (= 0.69.3)
- React-jsi (= 0.69.3)
- React-jsiexecutor (= 0.69.3)
- React-jsinspector (= 0.69.3)
- React-perflogger (= 0.69.3)
- React-jsi (0.69.3):
- React-cxxreact (= 0.69.4)
- React-jsi (= 0.69.4)
- React-jsiexecutor (= 0.69.4)
- React-jsinspector (= 0.69.4)
- React-perflogger (= 0.69.4)
- React-jsi (0.69.4):
- boost (= 1.76.0)
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-jsi/Default (= 0.69.3)
- React-jsi/Default (0.69.3):
- React-jsi/Default (= 0.69.4)
- React-jsi/Default (0.69.4):
- boost (= 1.76.0)
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-jsiexecutor (0.69.3):
- React-jsiexecutor (0.69.4):
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-cxxreact (= 0.69.3)
- React-jsi (= 0.69.3)
- React-perflogger (= 0.69.3)
- React-jsinspector (0.69.3)
- React-logger (0.69.3):
- React-cxxreact (= 0.69.4)
- React-jsi (= 0.69.4)
- React-perflogger (= 0.69.4)
- React-jsinspector (0.69.4)
- React-logger (0.69.4):
- glog
- react-native-safe-area-context (4.3.1):
- RCT-Folly
@ -263,74 +263,76 @@ PODS:
- RCTTypeSafety
- React
- ReactCommon/turbomodule/core
- React-perflogger (0.69.3)
- React-RCTActionSheet (0.69.3):
- React-Core/RCTActionSheetHeaders (= 0.69.3)
- React-RCTAnimation (0.69.3):
- React-perflogger (0.69.4)
- React-RCTActionSheet (0.69.4):
- React-Core/RCTActionSheetHeaders (= 0.69.4)
- React-RCTAnimation (0.69.4):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.69.3)
- React-Codegen (= 0.69.3)
- React-Core/RCTAnimationHeaders (= 0.69.3)
- React-jsi (= 0.69.3)
- ReactCommon/turbomodule/core (= 0.69.3)
- React-RCTBlob (0.69.3):
- RCTTypeSafety (= 0.69.4)
- React-Codegen (= 0.69.4)
- React-Core/RCTAnimationHeaders (= 0.69.4)
- React-jsi (= 0.69.4)
- ReactCommon/turbomodule/core (= 0.69.4)
- React-RCTBlob (0.69.4):
- RCT-Folly (= 2021.06.28.00-v2)
- React-Codegen (= 0.69.3)
- React-Core/RCTBlobHeaders (= 0.69.3)
- React-Core/RCTWebSocket (= 0.69.3)
- React-jsi (= 0.69.3)
- React-RCTNetwork (= 0.69.3)
- ReactCommon/turbomodule/core (= 0.69.3)
- React-RCTImage (0.69.3):
- React-Codegen (= 0.69.4)
- React-Core/RCTBlobHeaders (= 0.69.4)
- React-Core/RCTWebSocket (= 0.69.4)
- React-jsi (= 0.69.4)
- React-RCTNetwork (= 0.69.4)
- ReactCommon/turbomodule/core (= 0.69.4)
- React-RCTImage (0.69.4):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.69.3)
- React-Codegen (= 0.69.3)
- React-Core/RCTImageHeaders (= 0.69.3)
- React-jsi (= 0.69.3)
- React-RCTNetwork (= 0.69.3)
- ReactCommon/turbomodule/core (= 0.69.3)
- React-RCTLinking (0.69.3):
- React-Codegen (= 0.69.3)
- React-Core/RCTLinkingHeaders (= 0.69.3)
- React-jsi (= 0.69.3)
- ReactCommon/turbomodule/core (= 0.69.3)
- React-RCTNetwork (0.69.3):
- RCTTypeSafety (= 0.69.4)
- React-Codegen (= 0.69.4)
- React-Core/RCTImageHeaders (= 0.69.4)
- React-jsi (= 0.69.4)
- React-RCTNetwork (= 0.69.4)
- ReactCommon/turbomodule/core (= 0.69.4)
- React-RCTLinking (0.69.4):
- React-Codegen (= 0.69.4)
- React-Core/RCTLinkingHeaders (= 0.69.4)
- React-jsi (= 0.69.4)
- ReactCommon/turbomodule/core (= 0.69.4)
- React-RCTNetwork (0.69.4):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.69.3)
- React-Codegen (= 0.69.3)
- React-Core/RCTNetworkHeaders (= 0.69.3)
- React-jsi (= 0.69.3)
- ReactCommon/turbomodule/core (= 0.69.3)
- React-RCTSettings (0.69.3):
- RCTTypeSafety (= 0.69.4)
- React-Codegen (= 0.69.4)
- React-Core/RCTNetworkHeaders (= 0.69.4)
- React-jsi (= 0.69.4)
- ReactCommon/turbomodule/core (= 0.69.4)
- React-RCTSettings (0.69.4):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.69.3)
- React-Codegen (= 0.69.3)
- React-Core/RCTSettingsHeaders (= 0.69.3)
- React-jsi (= 0.69.3)
- ReactCommon/turbomodule/core (= 0.69.3)
- React-RCTText (0.69.3):
- React-Core/RCTTextHeaders (= 0.69.3)
- React-RCTVibration (0.69.3):
- RCTTypeSafety (= 0.69.4)
- React-Codegen (= 0.69.4)
- React-Core/RCTSettingsHeaders (= 0.69.4)
- React-jsi (= 0.69.4)
- ReactCommon/turbomodule/core (= 0.69.4)
- React-RCTText (0.69.4):
- React-Core/RCTTextHeaders (= 0.69.4)
- React-RCTVibration (0.69.4):
- RCT-Folly (= 2021.06.28.00-v2)
- React-Codegen (= 0.69.3)
- React-Core/RCTVibrationHeaders (= 0.69.3)
- React-jsi (= 0.69.3)
- ReactCommon/turbomodule/core (= 0.69.3)
- React-runtimeexecutor (0.69.3):
- React-jsi (= 0.69.3)
- ReactCommon/turbomodule/core (0.69.3):
- React-Codegen (= 0.69.4)
- React-Core/RCTVibrationHeaders (= 0.69.4)
- React-jsi (= 0.69.4)
- ReactCommon/turbomodule/core (= 0.69.4)
- React-runtimeexecutor (0.69.4):
- React-jsi (= 0.69.4)
- ReactCommon/turbomodule/core (0.69.4):
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-bridging (= 0.69.3)
- React-callinvoker (= 0.69.3)
- React-Core (= 0.69.3)
- React-cxxreact (= 0.69.3)
- React-jsi (= 0.69.3)
- React-logger (= 0.69.3)
- React-perflogger (= 0.69.3)
- React-bridging (= 0.69.4)
- React-callinvoker (= 0.69.4)
- React-Core (= 0.69.4)
- React-cxxreact (= 0.69.4)
- React-jsi (= 0.69.4)
- React-logger (= 0.69.4)
- React-perflogger (= 0.69.4)
- RNCAsyncStorage (1.17.7):
- React-Core
- RNCMaskedView (0.2.7):
- React-Core
- RNGestureHandler (2.5.0):
- React-Core
- RNReanimated (2.9.1):
@ -363,21 +365,21 @@ PODS:
- RNScreens (3.15.0):
- React-Core
- React-RCTImage
- RNSVG (12.4.3):
- RNSVG (13.0.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`)
- "EXApplication (from `../node_modules/.pnpm/expo-application@4.2.2_expo@46.0.2/node_modules/expo-application/ios`)"
- "EXConstants (from `../node_modules/.pnpm/expo-constants@13.2.3_expo@46.0.2/node_modules/expo-constants/ios`)"
- "EXFileSystem (from `../node_modules/.pnpm/expo-file-system@14.1.0_expo@46.0.2/node_modules/expo-file-system/ios`)"
- "EXFont (from `../node_modules/.pnpm/expo-font@10.2.0_expo@46.0.2/node_modules/expo-font/ios`)"
- "Expo (from `../node_modules/.pnpm/expo@46.0.2_@babel+core@7.18.10/node_modules/expo`)"
- "ExpoKeepAwake (from `../node_modules/.pnpm/expo-keep-awake@10.2.0_expo@46.0.2/node_modules/expo-keep-awake/ios`)"
- "ExpoModulesCore (from `../node_modules/.pnpm/expo-modules-core@0.11.3/node_modules/expo-modules-core/ios`)"
- "EXSplashScreen (from `../node_modules/.pnpm/expo-splash-screen@0.16.1_expo@46.0.2/node_modules/expo-splash-screen/ios`)"
- "EXApplication (from `../node_modules/.pnpm/expo-application@4.2.2_expo@46.0.9/node_modules/expo-application/ios`)"
- "EXConstants (from `../node_modules/.pnpm/expo-constants@13.2.3_expo@46.0.9/node_modules/expo-constants/ios`)"
- "EXFileSystem (from `../node_modules/.pnpm/expo-file-system@14.1.0_expo@46.0.9/node_modules/expo-file-system/ios`)"
- "EXFont (from `../node_modules/.pnpm/expo-font@10.2.0_expo@46.0.9/node_modules/expo-font/ios`)"
- "Expo (from `../node_modules/.pnpm/expo@46.0.9_@babel+core@7.18.10/node_modules/expo`)"
- "ExpoKeepAwake (from `../node_modules/.pnpm/expo-keep-awake@10.2.0_expo@46.0.9/node_modules/expo-keep-awake/ios`)"
- "ExpoModulesCore (from `../node_modules/.pnpm/expo-modules-core@0.11.4/node_modules/expo-modules-core/ios`)"
- "EXSplashScreen (from `../node_modules/.pnpm/expo-splash-screen@0.16.2_expo@46.0.9/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`)
@ -413,6 +415,7 @@ DEPENDENCIES:
- 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`)"
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- RNReanimated (from `../node_modules/react-native-reanimated`)
- RNScreens (from `../node_modules/react-native-screens`)
@ -430,21 +433,21 @@ EXTERNAL SOURCES:
DoubleConversion:
:podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
EXApplication:
:path: "../node_modules/.pnpm/expo-application@4.2.2_expo@46.0.2/node_modules/expo-application/ios"
:path: "../node_modules/.pnpm/expo-application@4.2.2_expo@46.0.9/node_modules/expo-application/ios"
EXConstants:
:path: "../node_modules/.pnpm/expo-constants@13.2.3_expo@46.0.2/node_modules/expo-constants/ios"
:path: "../node_modules/.pnpm/expo-constants@13.2.3_expo@46.0.9/node_modules/expo-constants/ios"
EXFileSystem:
:path: "../node_modules/.pnpm/expo-file-system@14.1.0_expo@46.0.2/node_modules/expo-file-system/ios"
:path: "../node_modules/.pnpm/expo-file-system@14.1.0_expo@46.0.9/node_modules/expo-file-system/ios"
EXFont:
:path: "../node_modules/.pnpm/expo-font@10.2.0_expo@46.0.2/node_modules/expo-font/ios"
:path: "../node_modules/.pnpm/expo-font@10.2.0_expo@46.0.9/node_modules/expo-font/ios"
Expo:
:path: "../node_modules/.pnpm/expo@46.0.2_@babel+core@7.18.10/node_modules/expo"
:path: "../node_modules/.pnpm/expo@46.0.9_@babel+core@7.18.10/node_modules/expo"
ExpoKeepAwake:
:path: "../node_modules/.pnpm/expo-keep-awake@10.2.0_expo@46.0.2/node_modules/expo-keep-awake/ios"
:path: "../node_modules/.pnpm/expo-keep-awake@10.2.0_expo@46.0.9/node_modules/expo-keep-awake/ios"
ExpoModulesCore:
:path: "../node_modules/.pnpm/expo-modules-core@0.11.3/node_modules/expo-modules-core/ios"
:path: "../node_modules/.pnpm/expo-modules-core@0.11.4/node_modules/expo-modules-core/ios"
EXSplashScreen:
:path: "../node_modules/.pnpm/expo-splash-screen@0.16.1_expo@46.0.2/node_modules/expo-splash-screen/ios"
:path: "../node_modules/.pnpm/expo-splash-screen@0.16.2_expo@46.0.9/node_modules/expo-splash-screen/ios"
FBLazyVector:
:path: "../node_modules/react-native/Libraries/FBLazyVector"
FBReactNativeSpec:
@ -511,6 +514,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon"
RNCAsyncStorage:
:path: "../node_modules/@react-native-async-storage/async-storage"
RNCMaskedView:
:path: "../node_modules/@react-native-masked-view/masked-view"
RNGestureHandler:
:path: "../node_modules/react-native-gesture-handler"
RNReanimated:
@ -529,50 +534,51 @@ SPEC CHECKSUMS:
EXConstants: 75c40827af38bd6bfcf69f880a5b45037eeff9c9
EXFileSystem: 927e0a8885aa9c49e50fc38eaba2c2389f2f1019
EXFont: a5d80bd9b3452b2d5abbce2487da89b0150e6487
Expo: a2d9d4d17b9c97beab797c54220b305708f60e87
Expo: 73412414e62f5cbc6e713def821de70b92cd3ad6
ExpoKeepAwake: 0e8f18142e71bbf2c7f6aa66ebed249ba1420320
ExpoModulesCore: 8303cc952788be09fc6eab62815d257016ae6dec
EXSplashScreen: 31ab6df6d23e97e074d1330224741979943f1d82
FBLazyVector: 1d83d91816fa605d16227a83f1b2e71c8df09d22
FBReactNativeSpec: 06454fe46192886c1bc472593057015292ba37ee
ExpoModulesCore: e281bb7b78ea47e227dd5af94d04b24d8b2e1255
EXSplashScreen: 799bece80089219b2c989c1082d70f3b00995cda
FBLazyVector: c71b8c429a8af2aff1013934a7152e9d9d0c937d
FBReactNativeSpec: 3cc5cff7d792e74a875be91e56d6242335016f50
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: 3d02b25ca00c2d456734d0bcff864cbc62f6ae1a
hermes-engine: ff1ba576165861a94a0d101b0a351a8ca2149f36
hermes-engine: 761a544537e62df2a37189389b9d2654dc1f75af
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
RCT-Folly: b9d9fe1fc70114b751c076104e52f3b1b5e5a95a
RCTRequired: 66822c147facf02f7774af99825e0a31e39df42e
RCTTypeSafety: 309306c4e711b14a83c55c2816a6cc490ec19827
React: a779632422a918b26db4f1b57225a41c14d20525
React-bridging: 96055aa45f0417898d7833e251f4ae79d28acef7
React-callinvoker: 02df4d620df286381ff3f99180fb24feceaf01cc
React-Codegen: 06613a5e753c3af2dca0d6e7dd02944a3d77c3f6
React-Core: 638d54d64048aa635e7c583fb0d8425206f446b4
React-CoreModules: f706ec2a1939387517cadc6ce0d2ef0f20fccb53
React-cxxreact: ec183b7f6fec01e7167f38c1c64a03f68dca7fb2
React-hermes: a97962948f74aaefffd4fe00bdafafbc245b08af
React-jsi: ed7dc77f5193dca9c73cec90bfec409e7ddfe401
React-jsiexecutor: 1842ca163b160aeb224d2c65b2a60c393b273c67
React-jsinspector: bb2605f98aada5d81f3494690da3ef3b4ff3b716
React-logger: 23a50ef4c18bf9adbb51e2c979318e6b3a2e44a1
RCTRequired: bd9d2ab0fda10171fcbcf9ba61a7df4dc15a28f4
RCTTypeSafety: e44e139bf6ec8042db396201834fc2372f6a21cd
React: 482cd1ba23c471be1aed3800180be2427418d7be
React-bridging: c2ea4fed6fe4ed27c12fd71e88b5d5d3da107fde
React-callinvoker: d4d1f98163fb5e35545e910415ef6c04796bb188
React-Codegen: ff35fb9c7f6ec2ed34fb6de2e1099d88dfb25f2f
React-Core: 4d3443a45b67c71d74d7243ddde9569d1e4f4fad
React-CoreModules: 70be25399366b5632ab18ecf6fe444a8165a7bea
React-cxxreact: 822d3794fc0bf206f4691592f90e086dd4f92228
React-hermes: 7f67b8363288258c3b0cd4aef5975cb7f0b9549a
React-jsi: ffa51cbc9a78cc156cf61f79ed52ecb76dc6013b
React-jsiexecutor: a27badbbdbc0ff781813370736a2d1c7261181d4
React-jsinspector: 8a3d3f5dcd23a91e8c80b1bf0e96902cd1dca999
React-logger: 1088859f145b8f6dd0d3ed051a647ef0e3e80fad
react-native-safe-area-context: 6c12e3859b6f27b25de4fee8201cfb858432d8de
React-perflogger: 39d2ba8cbcac54d1bb1d9a980dab348e96aef467
React-RCTActionSheet: b1ad907a2c8f8e4d037148ca507b7f2d6ab1c66d
React-RCTAnimation: 914a9ba46fb6e7376f7709c7ce825d53b47ca2ee
React-RCTBlob: de62fd5edc5c36951f0b113bf252eb43b7131f79
React-RCTImage: aa0749a8d748b34942c7e71ac5d9f42be8b70cf3
React-RCTLinking: 595a9f8fbf4d6634bff28d1175b3523b61466612
React-RCTNetwork: 0559fd0fccb01f89c638baa43c8d185dc8008626
React-RCTSettings: 8e492a25a62f1ef6323f82ce652ae87fa59c82ca
React-RCTText: 17457cde6ef8832ba43c886baebb6627c5d7ed18
React-RCTVibration: dd8099eb46e9cee4692934bc8cbe5e9a4f5e8d31
React-runtimeexecutor: 607eb048e22a16388c908ee1f6644200e8d1e19b
ReactCommon: af7636436b382db7cde4583bbd642f0978e6e3ed
React-perflogger: cb386fd44c97ec7f8199c04c12b22066b0f2e1e0
React-RCTActionSheet: f803a85e46cf5b4066c2ac5e122447f918e9c6e5
React-RCTAnimation: 19c80fa950ccce7f4db76a2a7f2cf79baae07fc7
React-RCTBlob: f36ab97e2d515c36df14a1571e50056be80413d5
React-RCTImage: 2c8f0a329a116248e82f8972ffe806e47c6d1cfa
React-RCTLinking: 670f0223075aff33be3b89714f1da4f5343fc4af
React-RCTNetwork: 09385b73f4ff1f46bd5d749540fb33f69a7e5908
React-RCTSettings: 33b12d3ac7a1f2eba069ec7bd1b84345263b3bbe
React-RCTText: a1a3ea902403bd9ae4cf6f7960551dc1d25711b5
React-RCTVibration: 9adb4a3cbb598d1bbd46a05256f445e4b8c70603
React-runtimeexecutor: 61ee22a8cdf8b6bb2a7fb7b4ba2cc763e5285196
ReactCommon: 8f67bd7e0a6afade0f20718f859dc8c2275f2e83
RNCAsyncStorage: d81ee5c3db1060afd49ea7045ad460eff82d2b7d
RNCMaskedView: cb9670ea9239998340eaab21df13fa12a1f9de15
RNGestureHandler: bad495418bcbd3ab47017a38d93d290ebd406f50
RNReanimated: 2cf7451318bb9cc430abeec8d67693f9cf4e039c
RNScreens: 4a1af06327774490d97342c00aee0c2bafb497b7
RNSVG: f3b60aeeaa81960e2e0536c3a9eef50b667ef3a9
Yoga: 44c64131616253fa83366295acdbce3d14926041
RNSVG: 42a0c731b11179ebbd27a3eeeafa7201ebb476ff
Yoga: ff994563b2fd98c982ca58e8cd9db2cdaf4dda74
PODFILE CHECKSUM: b77befb1871220c1a94408eeae0857d78b685698

View file

@ -3,36 +3,38 @@
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
08C620EC6F30A0663310BBC1 /* libPods-Spacedrive.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 080FB394AD883D9705C115A6 /* libPods-Spacedrive.a */; };
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */; };
519D1250147D911454D7DB76 /* libPods-Spacedrive.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F3F276D840CDBF9D0D9D548D /* libPods-Spacedrive.a */; };
5574975428A2496C00851D5A /* SDCore.m in Sources */ = {isa = PBXBuildFile; fileRef = 5574975328A2496C00851D5A /* SDCore.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
BB2F792D24A3F905000567C9 /* Expo.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB2F792C24A3F905000567C9 /* Expo.plist */; };
C95AE27BB525EFF3F02CEC11 /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56E71A6EFA9EA8F4C11F42FA /* ExpoModulesProvider.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = "<group>"; };
080FB394AD883D9705C115A6 /* libPods-Spacedrive.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Spacedrive.a"; sourceTree = BUILT_PRODUCTS_DIR; };
13B07F961A680F5B00A75B9A /* Spacedrive.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Spacedrive.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AppDelegate.mm; sourceTree = "<group>"; };
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
5574975328A2496C00851D5A /* SDCore.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDCore.m; sourceTree = "<group>"; };
5574975528A2498000851D5A /* SDCore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDCore.h; sourceTree = "<group>"; };
5574975628A24E0D00851D5A /* sdcore-universal-ios.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "sdcore-universal-ios.a"; path = "../../../target/sdcore-universal-ios.a"; sourceTree = "<group>"; };
56E71A6EFA9EA8F4C11F42FA /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-Spacedrive/ExpoModulesProvider.swift"; sourceTree = "<group>"; };
6C2E3173556A471DD304B334 /* Pods-mobilenew.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-mobilenew.debug.xcconfig"; path = "Target Support Files/Pods-mobilenew/Pods-mobilenew.debug.xcconfig"; sourceTree = "<group>"; };
78E58D73F5113B1BD543EE4D /* Pods-Spacedrive.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Spacedrive.debug.xcconfig"; path = "Target Support Files/Pods-Spacedrive/Pods-Spacedrive.debug.xcconfig"; sourceTree = "<group>"; };
7A4D352CD337FB3A3BF06240 /* Pods-mobilenew.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-mobilenew.release.xcconfig"; path = "Target Support Files/Pods-mobilenew/Pods-mobilenew.release.xcconfig"; sourceTree = "<group>"; };
AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = SplashScreen.storyboard; sourceTree = "<group>"; };
BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Expo.plist; path = Supporting/Expo.plist; sourceTree = "<group>"; };
D8F0094C07EEE7528760BD08 /* Pods-Spacedrive.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Spacedrive.release.xcconfig"; path = "Target Support Files/Pods-Spacedrive/Pods-Spacedrive.release.xcconfig"; sourceTree = "<group>"; };
CD5534017C1F13AB6E57EC53 /* Pods-Spacedrive.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Spacedrive.debug.xcconfig"; path = "Target Support Files/Pods-Spacedrive/Pods-Spacedrive.debug.xcconfig"; sourceTree = "<group>"; };
E661E5E8069E06E621509713 /* Pods-Spacedrive.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Spacedrive.release.xcconfig"; path = "Target Support Files/Pods-Spacedrive/Pods-Spacedrive.release.xcconfig"; sourceTree = "<group>"; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
F3F276D840CDBF9D0D9D548D /* libPods-Spacedrive.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Spacedrive.a"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -40,7 +42,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
519D1250147D911454D7DB76 /* libPods-Spacedrive.a in Frameworks */,
08C620EC6F30A0663310BBC1 /* libPods-Spacedrive.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -58,6 +60,8 @@
13B07FB61A68108700A75B9A /* Info.plist */,
13B07FB71A68108700A75B9A /* main.m */,
AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */,
5574975328A2496C00851D5A /* SDCore.m */,
5574975528A2498000851D5A /* SDCore.h */,
);
path = Spacedrive;
sourceTree = "<group>";
@ -73,8 +77,9 @@
2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
isa = PBXGroup;
children = (
5574975628A24E0D00851D5A /* sdcore-universal-ios.a */,
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
F3F276D840CDBF9D0D9D548D /* libPods-Spacedrive.a */,
080FB394AD883D9705C115A6 /* libPods-Spacedrive.a */,
);
name = Frameworks;
sourceTree = "<group>";
@ -120,10 +125,8 @@
D65327D7A22EEC0BE12398D9 /* Pods */ = {
isa = PBXGroup;
children = (
6C2E3173556A471DD304B334 /* Pods-mobilenew.debug.xcconfig */,
7A4D352CD337FB3A3BF06240 /* Pods-mobilenew.release.xcconfig */,
78E58D73F5113B1BD543EE4D /* Pods-Spacedrive.debug.xcconfig */,
D8F0094C07EEE7528760BD08 /* Pods-Spacedrive.release.xcconfig */,
CD5534017C1F13AB6E57EC53 /* Pods-Spacedrive.debug.xcconfig */,
E661E5E8069E06E621509713 /* Pods-Spacedrive.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@ -143,14 +146,15 @@
isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Spacedrive" */;
buildPhases = (
08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */,
9F553C6F8AA059AB72DAA720 /* [CP] Check Pods Manifest.lock */,
FD10A7F022414F080027D42C /* Start Packager */,
55B1130D28AB3061006C377F /* Build Spacedrive Core */,
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */,
0D580678BEFB3E7EF09A2CFE /* [CP] Embed Pods Frameworks */,
C93832A891603A9ED877B5D2 /* [CP] Embed Pods Frameworks */,
20C3591E751EF7109AA55859 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@ -221,7 +225,50 @@
shellPath = /bin/sh;
shellScript = "export NODE_BINARY=node\n\n# The project root by default is one level up from the ios directory\nexport PROJECT_ROOT=\"$PROJECT_DIR\"/..\n\n`node --print \"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/react-native-xcode.sh'\"`\n";
};
08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */ = {
20C3591E751EF7109AA55859 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Spacedrive/Pods-Spacedrive-resources.sh",
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Spacedrive/Pods-Spacedrive-resources.sh\"\n";
showEnvVarsInLog = 0;
};
55B1130D28AB3061006C377F /* Build Spacedrive Core */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"../../../core/src/*.rs",
"../rust/src/*.rs",
"../../../core/src/*/*.rs",
);
name = "Build Spacedrive Core";
outputFileListPaths = (
);
outputPaths = (
"../../../target/sdcore-universal-ios.a",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/zsh;
shellScript = "set -e\n\nif [[ -n \"${DEVELOPER_SDK_DIR:-}\" ]]; then\n # Assume we're in Xcode, which means we're probably cross-compiling.\n # In this case, we need to add an extra library search path for build scripts and proc-macros,\n # which run on the host instead of the target.\n # (macOS Big Sur does not have linkable libraries in /usr/lib/.)\n export LIBRARY_PATH=\"${DEVELOPER_SDK_DIR}/MacOSX.sdk/usr/lib:${LIBRARY_PATH:-}\"\nfi\n\nCARGO_FLAGS=\nif [[ \"$BUILDVARIANT\" != \"debug\" ]]; then\n CARGO_FLAGS=--release\nfi\n\nTARGET_DIRECTORY=../../../target\nif [[ $PLATFORM_NAME = \"iphonesimulator\" ]]\nthen\n cargo build -p sdcore-lib $CARGO_FLAGS --lib --target aarch64-apple-ios-sim\n lipo -create -output $TARGET_DIRECTORY/libsdcore-iossim.a $TARGET_DIRECTORY/aarch64-apple-ios-sim/release/libsdcore.a\nelse\n cargo build -p sdcore-lib $CARGO_FLAGS --lib --target aarch64-apple-ios\n lipo -create -output $TARGET_DIRECTORY/libsdcore-ios.a $TARGET_DIRECTORY/aarch64-apple-ios/release/libsdcore.a\nfi\n";
};
9F553C6F8AA059AB72DAA720 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@ -243,7 +290,7 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
0D580678BEFB3E7EF09A2CFE /* [CP] Embed Pods Frameworks */ = {
C93832A891603A9ED877B5D2 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@ -261,26 +308,6 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Spacedrive/Pods-Spacedrive-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Spacedrive/Pods-Spacedrive-resources.sh",
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Spacedrive/Pods-Spacedrive-resources.sh\"\n";
showEnvVarsInLog = 0;
};
FD10A7F022414F080027D42C /* Start Packager */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@ -310,6 +337,7 @@
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */,
13B07FC11A68108700A75B9A /* main.m in Sources */,
C95AE27BB525EFF3F02CEC11 /* ExpoModulesProvider.swift in Sources */,
5574975428A2496C00851D5A /* SDCore.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -318,7 +346,7 @@
/* Begin XCBuildConfiguration section */
13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 78E58D73F5113B1BD543EE4D /* Pods-Spacedrive.debug.xcconfig */;
baseConfigurationReference = CD5534017C1F13AB6E57EC53 /* Pods-Spacedrive.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
@ -333,12 +361,73 @@
);
INFOPLIST_FILE = Spacedrive/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/DoubleConversion\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/EXApplication\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/EXFont\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/Expo\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/ExpoKeepAwake\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/ExpoModulesCore\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/RCTTypeSafety\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/RNCAsyncStorage\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/RNCMaskedView\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/RNGestureHandler\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/RNReanimated\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/RNSVG\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/RNScreens\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-Codegen\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-Core\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-CoreModules\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTAnimation\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTBlob\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTImage\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTLinking\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTNetwork\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTSettings\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTText\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTVibration\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-bridging\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-hermes\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-jsi\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-jsiexecutor\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-jsinspector\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-logger\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-perflogger\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/Yoga\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/fmt\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/glog\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/libevent\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-safe-area-context\"",
/usr/lib/swift,
../../../target,
);
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
"-lc++",
);
"OTHER_LDFLAGS[sdk=iphoneos*]" = (
"$(inherited)",
"-ObjC",
"-lc++",
"-lsdcore-ios",
);
"OTHER_LDFLAGS[sdk=iphonesimulator*]" = (
"$(inherited)",
"-ObjC",
"-lc++",
"-lsdcore-iossim",
);
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
PRODUCT_BUNDLE_IDENTIFIER = com.spacedrive.app;
PRODUCT_NAME = Spacedrive;
@ -351,7 +440,7 @@
};
13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = D8F0094C07EEE7528760BD08 /* Pods-Spacedrive.release.xcconfig */;
baseConfigurationReference = E661E5E8069E06E621509713 /* Pods-Spacedrive.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
@ -361,12 +450,73 @@
DEVELOPMENT_TEAM = 72SE38W7T9;
INFOPLIST_FILE = Spacedrive/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/DoubleConversion\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/EXApplication\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/EXFont\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/Expo\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/ExpoKeepAwake\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/ExpoModulesCore\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/RCTTypeSafety\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/RNCAsyncStorage\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/RNCMaskedView\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/RNGestureHandler\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/RNReanimated\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/RNSVG\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/RNScreens\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-Codegen\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-Core\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-CoreModules\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTAnimation\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTBlob\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTImage\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTLinking\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTNetwork\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTSettings\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTText\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTVibration\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-bridging\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-hermes\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-jsi\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-jsiexecutor\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-jsinspector\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-logger\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/React-perflogger\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/Yoga\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/fmt\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/glog\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/libevent\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-safe-area-context\"",
/usr/lib/swift,
../../../target,
);
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
"-lc++",
);
"OTHER_LDFLAGS[sdk=iphoneos*]" = (
"$(inherited)",
"-ObjC",
"-lc++",
"-lsdcore-ios",
);
"OTHER_LDFLAGS[sdk=iphonesimulator*]" = (
"$(inherited)",
"-ObjC",
"-lc++",
"-lsdcore-iossim",
);
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
PRODUCT_BUNDLE_IDENTIFIER = com.spacedrive.app;
PRODUCT_NAME = Spacedrive;
@ -425,7 +575,10 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
LD_RUNPATH_SEARCH_PATHS = (
/usr/lib/swift,
"$(inherited)",
);
LIBRARY_SEARCH_PATHS = "\"$(inherited)\"";
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
@ -476,7 +629,10 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
LD_RUNPATH_SEARCH_PATHS = (
/usr/lib/swift,
"$(inherited)",
);
LIBRARY_SEARCH_PATHS = "\"$(inherited)\"";
MTL_ENABLE_DEBUG_INFO = NO;
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";

View file

@ -1,77 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Spacedrive</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>0.0.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>spacedrive</string>
<string>com.spacedrive.app</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
<key>UILaunchStoryboardName</key>
<string>SplashScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIRequiresFullScreen</key>
<false/>
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleDefault</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIUserInterfaceStyle</key>
<string>Automatic</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>
<dict>
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>
</array>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Spacedrive</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>0.0.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>spacedrive</string>
<string>com.spacedrive.app</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
<key>UILaunchStoryboardName</key>
<string>SplashScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIRequiresFullScreen</key>
<false/>
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleDefault</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIUserInterfaceStyle</key>
<string>Automatic</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

View file

@ -0,0 +1,17 @@
//
// SDCore.h
// Spacedrive
//
// Created by Oscar Beaumont on 9/8/2022.
//
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
#ifndef SDCore_h
#define SDCore_h
@interface SDCore : RCTEventEmitter <RCTBridgeModule>
@end
#endif /* SDCore_h */

View file

@ -0,0 +1,81 @@
//
// SDCore.m
// Spacedrive
//
// This file will not work unless ARC is disabled. Do this by setting the compiler flag '-fno-objc-arc' on this file in Settings > Build Phases > Compile Sources.
// This file also expects the Spacedrive Rust library to be linked in Settings > Build Phases > Link Binary with Libraries. This is the crude way, you should link the core with custom linker flags so that you can do it conditonally based on target OS.
// This file also expects a Build Phase to be setup which compiles the Rust prior to linking the sdcore library to the IOS build.
// This file also expects you to add "remote-notification" to the list of your supported UIBackgroundModes in your Info.plist
//
// Created by Oscar Beaumont on 9/8/2022.
//
#import "SDCore.h"
#import <React/RCTLog.h>
// is a function defined in Rust which starts a listener for Rust events.
void register_core_event_listener(id objc_class);
// is a function defined in Rust which is responsible for handling messages from the frontend.
void sd_core_msg(const char* query, void* resolve);
// is called by Rust to determine the base directory to store data in. This is only done when initialising the Node.
const char* get_data_directory(void)
{
NSArray *dirPaths = dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
const char *docDir = [ [dirPaths objectAtIndex:0] UTF8String];
return docDir;
}
// is called by Rust with a void* to the resolve function (of type RCTPromiseResolveBlock) to call it.
// Due to 'RCTPromiseResolveBlock' being an Objective-C block it is hard to call from Rust.
void call_resolve(void *resolvePtr, const char* resultRaw)
{
RCTPromiseResolveBlock resolve = (__bridge RCTPromiseResolveBlock) resolvePtr;
NSString *result = [NSString stringWithUTF8String:resultRaw];
resolve(result);
[result release];
}
@implementation SDCore
{
bool registeredWithRust;
bool hasListeners;
}
-(void)startObserving {
if (!registeredWithRust)
{
register_core_event_listener(self);
registeredWithRust = true;
}
hasListeners = YES;
}
-(void)stopObserving {
hasListeners = NO;
}
- (void)sendCoreEvent: (NSString*)query {
if (hasListeners) {
[self sendEventWithName:@"SDCoreEvent" body:query];
}
}
- (NSArray<NSString *> *)supportedEvents {
return @[@"SDCoreEvent"];
}
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(sd_core_msg: (NSString *)queryRaw
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
const char *query = [queryRaw UTF8String];
sd_core_msg(query, (__bridge void*) [resolve retain]);
}
@end

View file

@ -3,7 +3,6 @@ const MetroSymlinksResolver = require('@rnx-kit/metro-resolver-symlinks');
// Might not need these anymore.
const [SDAssetsPath, SDAssetsPathExclude] = resolveUniqueModule('@sd/assets', '.');
const [SDCorePath, SDCorePathExclude] = resolveUniqueModule('@sd/core', '.');
const [babelRuntimePath, babelRuntimeExclude] = resolveUniqueModule('@babel/runtime');
const [reactPath, reactExclude] = resolveUniqueModule('react');
@ -21,7 +20,6 @@ const metroConfig = makeMetroConfig({
extraNodeModules: {
'@babel/runtime': babelRuntimePath,
'@sd/assets': SDAssetsPath,
'@sd/core': SDCorePath,
'react': reactPath,
'react-native-svg': reactSVGPath
},
@ -29,7 +27,6 @@ const metroConfig = makeMetroConfig({
blockList: exclusionList([
babelRuntimeExclude,
SDAssetsPathExclude,
SDCorePathExclude,
reactExclude,
reactSVGExclude
]),

View file

@ -4,7 +4,7 @@
"main": "index.js",
"license": "GPL-3.0-only",
"scripts": {
"dev": "expo start --dev-client",
"start": "expo start --dev-client",
"android": "expo run:android",
"ios": "expo run:ios",
"lint": "eslint src/**/*.{ts,tsx} && tsc --noEmit"
@ -12,42 +12,45 @@
"dependencies": {
"@expo/vector-icons": "^13.0.0",
"@gorhom/bottom-sheet": "^4.4.3",
"@react-native-async-storage/async-storage": "^1.17.7",
"@react-navigation/bottom-tabs": "^6.3.2",
"@react-navigation/drawer": "^6.4.3",
"@react-navigation/native": "^6.0.11",
"@react-navigation/native-stack": "^6.7.0",
"@react-native-async-storage/async-storage": "~1.17.3",
"@react-native-masked-view/masked-view": "0.2.7",
"@react-navigation/bottom-tabs": "^6.3.3",
"@react-navigation/drawer": "^6.4.4",
"@react-navigation/native": "^6.0.12",
"@react-navigation/stack": "^6.2.3",
"@rspc/client": "^0.0.5",
"@sd/assets": "file:../../packages/assets",
"@sd/core": "file:../../core",
"@tanstack/react-query": "^4.2.3",
"byte-size": "^8.1.0",
"class-variance-authority": "^0.2.3",
"expo": "~46.0.2",
"expo-font": "^10.2.0",
"expo-linking": "^3.2.2",
"expo-splash-screen": "~0.16.1",
"date-fns": "^2.29.2",
"expo": "~46.0.9",
"expo-font": "~10.2.0",
"expo-linking": "~3.2.2",
"expo-splash-screen": "~0.16.2",
"expo-status-bar": "~1.4.0",
"intl": "^1.2.5",
"moti": "^0.18.0",
"phosphor-react-native": "^1.1.2",
"react": "18.2.0",
"react-native": "0.69.3",
"react-native-gesture-handler": "^2.5.0",
"react": "18.0.0",
"react-native": "0.69.4",
"react-native-gesture-handler": "~2.5.0",
"react-native-heroicons": "^2.2.0",
"react-native-reanimated": "^2.9.1",
"react-native-safe-area-context": "^4.3.1",
"react-native-screens": "^3.15.0",
"react-native-svg": "^12.3.0",
"react-native-reanimated": "~2.9.1",
"react-native-safe-area-context": "4.3.1",
"react-native-screens": "~3.15.0",
"react-native-svg": "13.0.0",
"twrnc": "^3.4.0",
"use-count-up": "^3.0.1",
"zustand": "^4.0.0"
"zustand": "^4.1.1"
},
"devDependencies": {
"@babel/core": "^7.12.9",
"@babel/core": "^7.18.6",
"@babel/runtime": "^7.18.9",
"@rnx-kit/metro-config": "^1.2.36",
"@rnx-kit/metro-resolver-symlinks": "^0.1.21",
"@types/react": "~18.0.15",
"@types/react-native": "~0.69.5",
"@types/react": "~18.0.0",
"@types/react-native": "~0.69.1",
"@typescript-eslint/eslint-plugin": "^5.30.7",
"@typescript-eslint/parser": "^5.30.7",
"eslint": "^8.21.0",
@ -55,8 +58,7 @@
"eslint-plugin-react": "^7.30.1",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-native": "^4.0.0",
"metro-minify-terser": "^0.72.0",
"react-native-svg": "^12.4.3",
"metro-minify-terser": "^0.72.1",
"react-native-svg-transformer": "^1.0.0",
"typescript": "^4.7.4"
},

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,27 @@
[package]
name = "sdcore-lib"
version = "0.1.0"
edition = "2021"
rust-version = "1.63.0"
[lib]
name = "sdcore"
crate-type = ["staticlib", "cdylib"] # staticlib for IOS and cdylib for Android
[dependencies]
once_cell = "1.13.0"
sdcore = { path = "../../../core", features = ["mobile", "p2p"], default-features = false }
rspc = { version = "0.0.4", features = [] }
serde_json = "1.0.83"
tokio = "1.20.1"
openssl = { version = "0.10.41", features = ["vendored"] } # Override features of transitive dependencies
openssl-sys = { version = "0.9.75", features = ["vendored"] } # Override features of transitive dependencies to support IOS Simulator on M1
[target.'cfg(target_os = "ios")'.dependencies]
objc = "0.2.7"
objc_id = "0.1.1"
objc-foundation = "0.1.1"
# This is `not(ios)` instead of `android` because of https://github.com/mozilla/rust-android-gradle/issues/93
[target.'cfg(not(target_os = "ios"))'.dependencies]
jni = "0.19.0"

View file

@ -0,0 +1,111 @@
use crate::{CLIENT_CONTEXT, EVENT_SENDER, NODE, RUNTIME};
use jni::objects::{JClass, JObject, JString};
use jni::JNIEnv;
use rspc::Request;
use sdcore::Node;
use tokio::sync::mpsc::unbounded_channel;
#[no_mangle]
pub extern "system" fn Java_com_spacedrive_app_SDCore_registerCoreEventListener(
env: JNIEnv,
class: JClass,
) {
let jvm = env.get_java_vm().unwrap();
let class = env.new_global_ref(class).unwrap();
let (tx, mut rx) = unbounded_channel();
let _ = EVENT_SENDER.set(tx);
RUNTIME.spawn(async move {
while let Some(event) = rx.recv().await {
let data = match serde_json::to_string(&event) {
Ok(json) => json,
Err(err) => {
println!("Failed to serialize event: {}", err);
continue;
},
};
let env = jvm.attach_current_thread().unwrap();
env.call_method(
&class,
"sendCoreEvent",
"(Ljava/lang/String;)V",
&[env
.new_string(data)
.expect("Couldn't create java string!")
.into()],
)
.unwrap();
}
});
}
#[no_mangle]
pub extern "system" fn Java_com_spacedrive_app_SDCore_handleCoreMsg(
env: JNIEnv,
class: JClass,
query: JString,
callback: JObject,
) {
let jvm = env.get_java_vm().unwrap();
let query: String = env
.get_string(query)
.expect("Couldn't get java string!")
.into();
let class = env.new_global_ref(class).unwrap();
let callback = env.new_global_ref(callback).unwrap();
RUNTIME.spawn(async move {
let request: Request = serde_json::from_str(&query).unwrap();
let node = &mut *NODE.lock().await;
let (node, router) = match node {
Some(node) => node.clone(),
None => {
let data_dir: String = {
let env = jvm.attach_current_thread().unwrap();
let data_dir = env
.call_method(
&class,
"getDataDirectory",
"()Ljava/lang/String;",
&[],
)
.unwrap()
.l()
.unwrap();
env.get_string(data_dir.into()).unwrap().into()
};
let new_node = Node::new(data_dir).await;
node.replace(new_node.clone());
new_node
},
};
let resp = serde_json::to_string(
&request
.handle(
node.get_request_context(),
&router,
&CLIENT_CONTEXT,
EVENT_SENDER.get(),
)
.await,
)
.unwrap();
let env = jvm.attach_current_thread().unwrap();
env.call_method(
&callback,
"resolve",
"(Ljava/lang/Object;)V",
&[env
.new_string(resp)
.expect("Couldn't create java string!")
.into()],
)
.unwrap();
});
}

View file

@ -0,0 +1,96 @@
use crate::{CLIENT_CONTEXT, EVENT_SENDER, NODE, RUNTIME};
use std::{
ffi::{CStr, CString},
os::raw::{c_char, c_void},
};
use tokio::sync::mpsc::unbounded_channel;
use objc::{class, msg_send, runtime::Object, sel, sel_impl};
use objc_foundation::{INSString, NSString};
use objc_id::Id;
use rspc::Request;
use sdcore::Node;
extern "C" {
fn get_data_directory() -> *const c_char;
fn call_resolve(resolve: *const c_void, result: *const c_char);
}
// This struct wraps the function pointer which represent a Javascript Promise. We wrap the
// function pointers in a struct so we can unsafely assert to Rust that they are `Send`.
// We know they are send as we have ensured Objective-C won't deallocate the function pointer
// until `call_resolve` is called.
struct RNPromise(*const c_void);
unsafe impl Send for RNPromise {}
impl RNPromise {
// resolve the promise
unsafe fn resolve(self, result: CString) {
call_resolve(self.0, result.as_ptr());
}
}
#[no_mangle]
pub unsafe extern "C" fn register_core_event_listener(id: *mut Object) {
let id = Id::<Object>::from_ptr(id);
let (tx, mut rx) = unbounded_channel();
let _ = EVENT_SENDER.set(tx);
RUNTIME.spawn(async move {
while let Some(event) = rx.recv().await {
let data = match serde_json::to_string(&event) {
Ok(json) => json,
Err(err) => {
println!("Failed to serialize event: {}", err);
continue;
},
};
let data = NSString::from_str(&data);
let _: () = msg_send![id, sendCoreEvent: data];
}
});
}
#[no_mangle]
pub unsafe extern "C" fn sd_core_msg(query: *const c_char, resolve: *const c_void) {
// This string is cloned to the Rust heap. This is important as Objective-C may remove the query once this function completions but prior to the async block finishing.
let query = CStr::from_ptr(query).to_str().unwrap().to_string();
let resolve = RNPromise(resolve);
RUNTIME.spawn(async move {
let request: Request = serde_json::from_str(&query).unwrap();
let node = &mut *NODE.lock().await;
let (node, router) = match node {
Some(node) => node.clone(),
None => {
let doc_dir = CStr::from_ptr(get_data_directory())
.to_str()
.unwrap()
.to_string();
let new_node = Node::new(doc_dir).await;
node.replace(new_node.clone());
new_node
},
};
resolve.resolve(
CString::new(
serde_json::to_vec(
&request
.handle(
node.get_request_context(),
&router,
&CLIENT_CONTEXT,
EVENT_SENDER.get(),
)
.await,
)
.unwrap(),
)
.unwrap(),
)
});
}

View file

@ -0,0 +1,31 @@
use std::sync::Arc;
use once_cell::sync::{Lazy, OnceCell};
use rspc::{ClientContext, Response};
use sdcore::{api::Router, Node};
use tokio::{
runtime::Runtime,
sync::{mpsc::UnboundedSender, Mutex},
};
#[allow(dead_code)]
pub(crate) static RUNTIME: Lazy<Runtime> = Lazy::new(|| Runtime::new().unwrap());
#[allow(dead_code)]
pub(crate) static NODE: Lazy<Mutex<Option<(Arc<Node>, Arc<Router>)>>> =
Lazy::new(|| Mutex::new(None));
#[allow(dead_code)]
pub(crate) static CLIENT_CONTEXT: Lazy<ClientContext> = Lazy::new(|| ClientContext {
subscriptions: Default::default(),
});
#[allow(dead_code)]
pub(crate) static EVENT_SENDER: OnceCell<UnboundedSender<Response>> = OnceCell::new();
#[cfg(target_os = "ios")]
mod ios;
/// This is `not(ios)` instead of `android` because of https://github.com/mozilla/rust-android-gradle/issues/93
#[cfg(not(target_os = "ios"))]
mod android;

View file

@ -1,18 +1,26 @@
import { BottomSheetModalProvider } from '@gorhom/bottom-sheet';
import { DefaultTheme, NavigationContainer, Theme } from '@react-navigation/native';
import { createClient } from '@rspc/client';
import { StatusBar } from 'expo-status-bar';
import React, { useEffect } from 'react';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { useDeviceContext } from 'twrnc';
import { GlobalModals } from './components/modals/GlobalModals';
import { ReactNativeTransport, queryClient, rspc, useInvalidateQuery } from './hooks/rspc';
import useCachedResources from './hooks/useCachedResources';
import { getItemFromStorage } from './lib/storage';
import tw from './lib/tailwind';
import RootNavigator from './navigation';
import OnboardingNavigator from './navigation/OnboardingNavigator';
import { useOnboardingStore } from './stores/useOnboardingStore';
import type { Operations } from './types/bindings';
const client = createClient<Operations>({
transport: new ReactNativeTransport()
});
//
const NavigatorTheme: Theme = {
...DefaultTheme,
colors: {
@ -41,14 +49,27 @@ export default function App() {
return null;
} else {
return (
<SafeAreaProvider style={tw`flex-1 bg-black`}>
<GestureHandlerRootView style={tw`flex-1`}>
<NavigationContainer theme={NavigatorTheme}>
{showOnboarding ? <OnboardingNavigator /> : <RootNavigator />}
</NavigationContainer>
<StatusBar style="light" />
</GestureHandlerRootView>
</SafeAreaProvider>
<rspc.Provider client={client} queryClient={queryClient}>
<>
<InvalidateQuery />
<SafeAreaProvider style={tw`flex-1 bg-black`}>
<GestureHandlerRootView style={tw`flex-1`}>
<BottomSheetModalProvider>
<StatusBar style="light" />
<NavigationContainer theme={NavigatorTheme}>
{showOnboarding ? <OnboardingNavigator /> : <RootNavigator />}
</NavigationContainer>
<GlobalModals />
</BottomSheetModalProvider>
</GestureHandlerRootView>
</SafeAreaProvider>
</>
</rspc.Provider>
);
}
}
function InvalidateQuery() {
useInvalidateQuery();
return null;
}

View file

@ -1,15 +0,0 @@
<svg style="width: 100%; height: auto;" viewBox="0 0 141 110" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 15.5273C0 7.15264 6.78899 0.363647 15.1636 0.363647H35.9094C39.3671 0.363647 42.7035 1.63836 45.2803 3.94395C47.8571 6.24955 51.1935 7.52425 54.6512 7.52425H123.836C132.211 7.52425 139 14.3132 139 22.6879V23.9515C139 32.3262 132.211 39.1152 123.836 39.1152H15.1636C6.78899 39.1152 0 32.3262 0 23.9515V15.5273Z" fill="url(#paint0_linear_0_3)"/>
<path d="M0 29.8485C0 23.8001 4.90316 18.897 10.9515 18.897H128.048C134.097 18.897 139 23.8001 139 29.8485V94.7152C139 103.09 132.211 109.879 123.836 109.879H15.1636C6.78899 109.879 0 103.09 0 94.7152V29.8485Z" fill="url(#paint1_linear_0_3)"/>
<path d="M0.582787 99.2818L140.005 100" stroke="white" stroke-opacity="0.03" stroke-width="2"/>
<defs>
<linearGradient id="paint0_linear_0_3" x1="69.5" y1="0.363647" x2="69.5" y2="39.1152" gradientUnits="userSpaceOnUse">
<stop stop-color="#E7E6E6"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<linearGradient id="paint1_linear_0_3" x1="69.5" y1="18.897" x2="69.5" y2="109.879" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#EAEAEA"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -1,16 +0,0 @@
<svg style="width: 100%; height: auto;" viewBox="0 0 141 110" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 15.5273C0 7.15264 6.78899 0.363647 15.1636 0.363647H35.9094C39.3671 0.363647 42.7035 1.63836 45.2803 3.94395V3.94395C47.8571 6.24955 51.1935 7.52425 54.6512 7.52425H123.836C132.211 7.52425 139 14.3132 139 22.6879V23.9515C139 32.3262 132.211 39.1152 123.836 39.1152H15.1636C6.78899 39.1152 0 32.3262 0 23.9515V15.5273Z" fill="url(#paint0_linear_13_627)"/>
<path d="M0 29.8485C0 23.8001 4.90316 18.897 10.9515 18.897H128.048C134.097 18.897 139 23.8001 139 29.8485V94.7152C139 103.09 132.211 109.879 123.836 109.879H15.1636C6.78899 109.879 0 103.09 0 94.7152V29.8485Z" fill="url(#paint1_linear_13_627)"/>
<line x1="0.424076" y1="97.8758" x2="139.002" y2="98.1576" stroke="black" stroke-opacity="0.13" stroke-width="1.68485"/>
<line x1="0.582788" y1="99.2818" x2="140.005" y2="100" stroke="white" stroke-opacity="0.03" stroke-width="2"/>
<defs>
<linearGradient id="paint0_linear_13_627" x1="69.5" y1="0.363647" x2="69.5" y2="39.1152" gradientUnits="userSpaceOnUse">
<stop stop-color="#2D82E7"/>
<stop offset="1" stop-color="#083258"/>
</linearGradient>
<linearGradient id="paint1_linear_13_627" x1="69.5" y1="18.897" x2="69.5" y2="109.879" gradientUnits="userSpaceOnUse">
<stop stop-color="#319DCB"/>
<stop offset="1" stop-color="#264BA8"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

View file

@ -0,0 +1,14 @@
import React from 'react';
import { StyleProp, Text, View, ViewStyle } from 'react-native';
import tw from '../../lib/tailwind';
type DividerProps = {
style?: StyleProp<ViewStyle>;
};
const Divider = ({ style }: DividerProps) => {
return <View style={[tw`w-full my-1 h-[1px] bg-gray-550`, style]} />;
};
export default Divider;

View file

@ -2,7 +2,7 @@ import React from 'react';
import { Pressable, Text, View } from 'react-native';
import tw from '../../lib/tailwind';
import FolderIcon from '../icons/Folder';
import FolderIcon from '../icons/FolderIcon';
interface BrowseLocationItemProps {
folderName: string;

View file

@ -1,19 +1,12 @@
import { FilePath } from '@sd/core';
import { Cloud, Desktop, DeviceMobileCamera, Laptop } from 'phosphor-react-native';
import React from 'react';
import { FlatList, Text, View } from 'react-native';
import { LockClosedIcon } from 'react-native-heroicons/solid';
import tw from '../../lib/tailwind';
import { FilePath } from '../../types/bindings';
import FileItem from '../file/FileItem';
export interface DeviceProps {
name: string;
size: string;
type: 'laptop' | 'desktop' | 'phone' | 'server';
locations: Array<{ name: string; folder?: boolean; format?: string; icon?: string }>;
}
const placeholderFileItems: FilePath[] = [
{
is_dir: true,
@ -272,10 +265,18 @@ const placeholderFileItems: FilePath[] = [
}
];
export interface DeviceProps {
name: string;
size: string;
type: 'laptop' | 'desktop' | 'phone' | 'server';
locations: { name: string; folder?: boolean; format?: string; icon?: string }[];
runningJob?: { amount: number; task: string };
}
const Device = ({ name, locations, size, type }: DeviceProps) => {
return (
<View style={tw`bg-gray-600 border rounded-md border-gray-550 my-2`}>
<View style={tw`flex flex-row items-center px-4 pt-3 pb-2`}>
<View style={tw`flex flex-row items-center px-3.5 pt-3 pb-2`}>
<View style={tw`flex flex-row items-center`}>
{type === 'phone' && (
<DeviceMobileCamera color="white" weight="fill" size={18} style={tw`mr-2`} />
@ -299,7 +300,7 @@ const Device = ({ name, locations, size, type }: DeviceProps) => {
renderItem={({ item }) => <FileItem file={item} />}
keyExtractor={(item) => item.id.toString()}
horizontal
contentContainerStyle={tw`mt-4 ml-2`}
contentContainerStyle={tw`mt-3 mb-5`}
showsHorizontalScrollIndicator={false}
/>
</View>

View file

@ -1,56 +1,110 @@
import { DrawerContentScrollView } from '@react-navigation/drawer';
import { DrawerContentComponentProps } from '@react-navigation/drawer/lib/typescript/src/types';
import { House } from 'phosphor-react-native';
import { getFocusedRouteNameFromRoute } from '@react-navigation/native';
import React from 'react';
import { Pressable, Text, View } from 'react-native';
import { ColorValue, Platform, Pressable, Text, View } from 'react-native';
import { CogIcon } from 'react-native-heroicons/solid';
import Layout from '../../constants/Layout';
import tw from '../../lib/tailwind';
import type { DrawerNavParamList } from '../../navigation/DrawerNavigator';
import { valueof } from '../../types/helper';
import DrawerItem from './DrawerItem';
import CollapsibleView from '../layout/CollapsibleView';
import DrawerLocationItem from './DrawerLocationItem';
import DrawerLogo from './DrawerLogo';
import DrawerTagItem from './DrawerTagItem';
const drawerHeight = Layout.window.height * 0.85;
const placeholderLocationData = [
{
id: 1,
name: 'Spacedrive'
},
{
id: 2,
name: 'Content'
}
];
const placeholderTagsData = [
{
id: 1,
name: 'Funny',
color: tw.color('blue-500')
},
{
id: 2,
name: 'Twitch',
color: tw.color('purple-500')
},
{
id: 3,
name: 'BlackMagic',
color: tw.color('red-500')
}
];
// This is a hacky way to get the active route name and params but it works and it's typed...
const drawerHeight = Platform.select({
ios: Layout.window.height * 0.85,
android: Layout.window.height * 0.9
});
interface ActiveRoute {
key: string;
name: keyof DrawerNavParamList;
params: valueof<Omit<DrawerNavParamList, 'Home'>>;
}
const getActiveRouteState = function (state: any): ActiveRoute {
const getActiveRouteState = function (state: any) {
if (!state.routes || state.routes.length === 0 || state.index >= state.routes.length) {
return state;
}
const childActiveRoute = state.routes[state.index];
return getActiveRouteState(childActiveRoute);
};
// Overriding the default to add typing for our params.
// interface DrawerContentComponentProps {
// state: DrawerNavigationState<DrawerNavParamList>;
// navigation: NavigationHelpers<DrawerNavParamList, DrawerNavigationEventMap> &
// DrawerActionHelpers<DrawerNavParamList>;
// // descriptors type is generic
// descriptors: DrawerDescriptorMap;
// }
const DrawerContent = ({ navigation, state }: DrawerContentComponentProps) => {
const stackName = getFocusedRouteNameFromRoute(getActiveRouteState(state)) ?? 'OverviewStack';
const DrawerContent = ({ descriptors, navigation, state }: DrawerContentComponentProps) => {
return (
<DrawerContentScrollView style={tw`flex-1 p-4`} scrollEnabled={false}>
<DrawerContentScrollView style={tw`flex-1 px-4 py-2`} scrollEnabled={false}>
<View style={tw.style('justify-between', { height: drawerHeight })}>
<View>
<Text style={tw`my-4 text-white`}>TODO: Library Selection</Text>
<DrawerItem
label={'Home'}
icon={<House size={20} color={'white'} weight="bold" />}
onPress={() => navigation.jumpTo('Home')}
isSelected={getActiveRouteState(state).name === 'Home'}
/>
<DrawerLogo />
<Text style={tw`my-4 text-white text-xs`}>TODO: Library Selection</Text>
{/* Locations */}
<CollapsibleView
title="Locations"
titleStyle={tw`mt-4 mb-3 ml-1 text-sm font-semibold text-gray-300`}
>
{placeholderLocationData.map((location) => (
<DrawerLocationItem
key={location.id}
folderName={location.name}
onPress={() =>
navigation.navigate(stackName, {
screen: 'Location',
params: { id: location.id }
})
}
/>
))}
{/* Add Location */}
<View style={tw`border border-dashed rounded border-gray-450 border-opacity-60 mt-1`}>
<Text style={tw`text-xs font-bold text-center text-gray-400 px-2 py-2`}>
Add Location
</Text>
</View>
</CollapsibleView>
{/* Tags */}
<CollapsibleView
title="Tags"
titleStyle={tw`mt-6 mb-3 ml-1 text-sm font-semibold text-gray-300`}
>
{placeholderTagsData.map((tag) => (
<DrawerTagItem
key={tag.id}
tagName={tag.name}
onPress={() =>
navigation.navigate(stackName, {
screen: 'Tag',
params: { id: tag.id }
})
}
tagColor={tag.color as ColorValue}
/>
))}
</CollapsibleView>
</View>
{/* Settings */}
<Pressable onPress={() => navigation.navigate('Settings')}>

View file

@ -1,34 +0,0 @@
import React from 'react';
import { Pressable, Text, View } from 'react-native';
import tw from '../../lib/tailwind';
interface DrawerProps {
label: string;
onPress: () => void;
icon: JSX.Element;
isSelected: boolean;
}
const DrawerItem: React.FC<DrawerProps> = (props) => {
const { label, icon, onPress, isSelected } = props;
return (
<Pressable onPress={onPress} style={tw``}>
<View
style={tw.style(
'flex mb-[4px] flex-row items-center py-2 px-2 rounded',
isSelected && 'bg-primary'
)}
>
{icon}
<Text
style={tw.style('text-gray-300 text-sm font-medium ml-2', isSelected && 'text-white')}
>
{label}
</Text>
</View>
</Pressable>
);
};
export default DrawerItem;

View file

@ -0,0 +1,26 @@
import React from 'react';
import { Pressable, Text, View } from 'react-native';
import tw from '../../lib/tailwind';
import FolderIcon from '../icons/FolderIcon';
interface DrawerLocationItemProps {
folderName: string;
onPress: () => void;
}
const DrawerLocationItem: React.FC<DrawerLocationItemProps> = (props) => {
const { folderName, onPress } = props;
return (
<Pressable onPress={onPress}>
<View style={tw.style('flex mb-[4px] flex-row items-center py-2 px-2 rounded')}>
<FolderIcon size={18} />
<Text style={tw.style('text-gray-300 text-sm font-medium ml-2')} numberOfLines={1}>
{folderName}
</Text>
</View>
</Pressable>
);
};
export default DrawerLocationItem;

View file

@ -0,0 +1,19 @@
import React from 'react';
import { Image, Text, View } from 'react-native';
import tw from '../../lib/tailwind';
import Divider from '../base/Divider';
const DrawerLogo = () => {
return (
<>
<View style={tw`flex flex-row items-center`}>
<Image source={require('@sd/assets/images/logo.png')} style={tw`w-9 h-9`} />
<Text style={tw`text-base font-bold text-white ml-2`}>Spacedrive</Text>
</View>
<Divider style={tw`mt-4`} />
</>
);
};
export default DrawerLogo;

View file

@ -1,31 +0,0 @@
import { useDrawerProgress } from '@react-navigation/drawer';
import React from 'react';
import Animated, { Extrapolate, interpolate, useAnimatedStyle } from 'react-native-reanimated';
import { SafeAreaView } from 'react-native-safe-area-context';
import tw from '../../lib/tailwind';
// NOTE: Only wrap screens that need the drawer to be open. (Only Overview Screen for now.)
const DrawerScreenWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const progress: any = useDrawerProgress();
const style = useAnimatedStyle(() => {
// TODO: Fix this, it looks weird. Especially on Android. translateX/Y might be the cause.
const scale = interpolate(progress.value, [0, 1], [1, 0.88], Extrapolate.CLAMP);
const translateX = interpolate(progress.value, [0, 1], [0, -12], Extrapolate.CLAMP);
const translateY = interpolate(progress.value, [0, 1], [0, 12], Extrapolate.CLAMP);
const borderRadius = interpolate(progress.value, [0, 1], [0, 16], Extrapolate.CLAMP);
return {
transform: [{ scale }, { translateX }, { translateY }],
borderRadius
};
}, []);
return (
<Animated.View style={[tw.style('flex-1 bg-[#121219]'), style]}>
<SafeAreaView edges={['top']}>{children}</SafeAreaView>
</Animated.View>
);
};
export default DrawerScreenWrapper;

View file

@ -0,0 +1,26 @@
import React from 'react';
import { ColorValue, Pressable, Text, View } from 'react-native';
import tw from '../../lib/tailwind';
type DrawerTagItemProps = {
tagName: string;
tagColor: ColorValue;
onPress: () => void;
};
const DrawerTagItem: React.FC<DrawerTagItemProps> = (props) => {
const { tagName, tagColor, onPress } = props;
return (
<Pressable onPress={onPress}>
<View style={tw.style('flex mb-[4px] flex-row items-center py-2 px-2 rounded')}>
<View style={tw.style('w-3 h-3 rounded-full', { backgroundColor: tagColor })} />
<Text style={tw.style('text-gray-300 text-sm font-medium ml-2')} numberOfLines={1}>
{tagName}
</Text>
</View>
</Pressable>
);
};
export default DrawerTagItem;

View file

@ -0,0 +1,73 @@
import React from 'react';
import { Text, View } from 'react-native';
import Svg, { Path } from 'react-native-svg';
import icons from '../../assets/icons/file';
import tw from '../../lib/tailwind';
import { FilePath } from '../../types/bindings';
import FolderIcon from '../icons/FolderIcon';
type FileIconProps = {
file?: FilePath | null;
/**
* This is multiplier for calculating icon size
* default: `1`
*/
size?: number;
};
const FileIcon = ({ file, size = 1 }: FileIconProps) => {
return (
<View style={[tw`justify-center`, { width: 60 * size, height: 60 * size }]}>
{file?.is_dir ? (
<View style={tw`items-center`}>
<FolderIcon size={50 * size} />
</View>
) : file?.file?.has_thumbnail ? (
<>{/* TODO */}</>
) : (
<View style={[tw`m-auto relative`, { width: 45 * size, height: 60 * size }]}>
<Svg
style={tw`absolute top-0 left-0`}
fill={tw.color('gray-550')}
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
style={tw`absolute top-[2px] -right-[0.6px]`}
fill={tw.color('gray-500')}
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`}>
{file?.extension &&
icons[file.extension] &&
(() => {
const Icon = icons[file.extension];
return <Icon width={18 * size} height={18 * size} style={tw`mt-2`} />;
})()}
<Text
style={[
tw`mt-1 font-bold text-center uppercase text-gray-450`,
{
fontSize: 10 * (size * 0.8)
}
]}
>
{file?.extension}
</Text>
</View>
</View>
)}
</View>
);
};
export default FileIcon;

View file

@ -1,76 +1,48 @@
import { FilePath } from '@sd/core';
import { useNavigation } from '@react-navigation/native';
import React from 'react';
import { Text, View } from 'react-native';
import Svg, { Path } from 'react-native-svg';
import { Pressable, Text, View } from 'react-native';
import icons from '../../assets/icons/file';
import tw from '../../lib/tailwind';
import FolderIcon from '../icons/Folder';
import { SharedScreenProps } from '../../navigation/SharedScreens';
import { useFileModalStore } from '../../stores/useModalStore';
import { FilePath } from '../../types/bindings';
import FileIcon from './FileIcon';
type FileItemProps = {
file?: FilePath | null;
};
// TODO: Menu for file actions (File details, Share etc.)
// TODO: Sheet Modal for file details
const FileItem = ({ file }: FileItemProps) => {
const fileRef = useFileModalStore((state) => state.fileRef);
const setData = useFileModalStore((state) => state.setData);
const navigation = useNavigation<SharedScreenProps<'Location'>['navigation']>();
function handlePress() {
if (!file) return;
if (file.is_dir) {
navigation.navigate('Location', { id: file.location_id });
} else {
setData(file);
fileRef.current.present();
}
}
return (
<View style={tw`w-[90px] h-[100px]`}>
<View style={tw`items-center`}>
<Pressable onPress={handlePress}>
<View style={tw`w-[90px] h-[80px] items-center`}>
{/* Folder Icons/Thumbnail etc. */}
<View style={tw`w-[60px] h-[60px] justify-center`}>
{file?.is_dir ? (
<View style={tw`items-center`}>
<FolderIcon size={54} />
</View>
) : file?.file?.has_thumbnail ? (
<>{/* TODO */}</>
) : (
<View style={tw`w-[45px] h-[60px] m-auto relative`}>
<Svg
style={tw`absolute top-0 left-0`}
fill={tw.color('gray-550')}
width={45}
height={60}
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
style={tw`absolute top-[2px] -right-[0.6px]`}
fill={tw.color('gray-500')}
width={15}
height={15}
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`}>
{file?.extension && icons[file.extension] ? (
(() => {
const Icon = icons[file.extension];
return <Icon width={18} height={18} style={tw`mt-2`} />;
})()
) : (
<></>
)}
<Text style={tw`mt-1 text-[10px] font-bold text-center uppercase text-gray-450`}>
{file?.extension}
</Text>
</View>
</View>
)}
</View>
{/* Name */}
<FileIcon file={file} />
<View style={tw`px-1.5 py-[1px] mt-1`}>
<Text numberOfLines={1} style={tw`text-gray-300 text-center text-xs font-medium`}>
{file?.name}
</Text>
</View>
</View>
</View>
</Pressable>
);
};

View file

@ -0,0 +1,41 @@
import { useDrawerStatus } from '@react-navigation/drawer';
import { DrawerNavigationHelpers } from '@react-navigation/drawer/lib/typescript/src/types';
import { useNavigation } from '@react-navigation/native';
import { MotiView } from 'moti';
import { List } from 'phosphor-react-native';
import React from 'react';
import { Pressable, Text, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import tw from '../../lib/tailwind';
const Header = () => {
const navigation = useNavigation<DrawerNavigationHelpers>();
const { top } = useSafeAreaInsets();
const isDrawerOpen = useDrawerStatus() === 'open';
return (
<View style={tw.style('mx-4 bg-gray-550 rounded-md', { marginTop: top + 10 })}>
<View style={tw`flex flex-row items-center h-10`}>
<Pressable style={tw`px-3 h-full justify-center`} onPress={() => navigation.openDrawer()}>
<MotiView
animate={{ rotate: isDrawerOpen ? '90deg' : '0deg' }}
transition={{ type: 'timing' }}
>
<List size={20} color={tw.color('gray-300')} weight="fill" />
</MotiView>
</Pressable>
<Pressable
style={tw`flex-1 h-full justify-center`}
onPress={() => navigation.navigate('Search')}
>
<Text style={tw`text-gray-300 font-semibold text-sm`}>Search</Text>
</Pressable>
</View>
</View>
);
};
export default Header;

View file

@ -1,9 +1,8 @@
import FolderWhite from '@sd/assets/svgs/folder-white.svg';
import Folder from '@sd/assets/svgs/folder.svg';
import React from 'react';
import { SvgProps } from 'react-native-svg';
import FolderWhite from '../../assets/temp/folder-white.svg';
import Folder from '../../assets/temp/folder.svg';
type FolderProps = {
/**
* Render a white folder icon

View file

@ -1 +0,0 @@
// Only mount this modal if `FileItem` gets used in screen.

View file

@ -0,0 +1,128 @@
import { BottomSheetModal, BottomSheetScrollView } from '@gorhom/bottom-sheet';
import { format } from 'date-fns';
import React, { useRef } from 'react';
import { Button, Pressable, Text, View } from 'react-native';
import { ChevronLeftIcon } from 'react-native-heroicons/outline';
import tw from '../../lib/tailwind';
import { useFileModalStore } from '../../stores/useModalStore';
import Divider from '../base/Divider';
import FileIcon from '../file/FileIcon';
import ModalBackdrop from './layout/ModalBackdrop';
import ModalHandle from './layout/ModalHandle';
/*
https://github.com/software-mansion/react-native-reanimated/issues/3296
https://github.com/gorhom/react-native-bottom-sheet/issues/925
https://github.com/gorhom/react-native-bottom-sheet/issues/1036
Reanimated has a bug where it sometimes doesn't animate on mount (IOS only?), doing a console.log() seems to do a re-render and fix the issue.
We can't do this for production obvs but until then they might fix it so, let's not try weird hacks for now and live with the logs.
*/
interface MetaItemProps {
title: string;
value: string;
}
function MetaItem({ title, value }: MetaItemProps) {
return (
<View>
<Text style={tw`text-sm font-bold text-white`}>{title}</Text>
<Text style={tw`text-sm text-gray-400 mt-1`}>{value}</Text>
</View>
);
}
export const FileModal = () => {
const { fileRef, data } = useFileModalStore();
const fileDetailsRef = useRef<BottomSheetModal>(null);
return (
<>
<BottomSheetModal
ref={fileRef}
snapPoints={['60%', '90%']}
backdropComponent={ModalBackdrop}
handleComponent={ModalHandle}
// Do not remove!
onAnimate={(from, to) => console.log(from, to)}
>
{data && (
<View style={tw`flex-1 p-4 bg-gray-600`}>
{/* File Icon / Name */}
<View style={tw`flex flex-row items-center`}>
<FileIcon file={data} size={1.6} />
{/* File Name, Details etc. */}
<View style={tw`ml-2`}>
<Text style={tw`text-base font-bold text-gray-200`}>{data?.name}</Text>
<View style={tw`flex flex-row mt-2`}>
<Text style={tw`text-xs text-gray-400`}>5 MB,</Text>
<Text style={tw`ml-1 text-xs text-gray-400`}>
{data?.extension.toUpperCase()},
</Text>
<Text style={tw`ml-1 text-xs text-gray-400`}>15 Aug</Text>
</View>
<Pressable style={tw`mt-2`} onPress={() => fileDetailsRef.current.present()}>
<Text style={tw`text-sm text-primary-500`}>More</Text>
</Pressable>
</View>
</View>
{/* Divider */}
<Divider style={tw`my-6`} />
{/* Buttons */}
<Button onPress={() => fileRef.current.close()} title="Copy" color="white" />
<Button onPress={() => fileRef.current.close()} title="Move" color="white" />
<Button onPress={() => fileRef.current.close()} title="Share" color="white" />
<Button onPress={() => fileRef.current.close()} title="Delete" color="white" />
</View>
)}
</BottomSheetModal>
{/* Details Modal */}
<BottomSheetModal
ref={fileDetailsRef}
enableContentPanningGesture={false}
enablePanDownToClose={false}
snapPoints={['70%']}
backdropComponent={ModalBackdrop}
handleComponent={ModalHandle}
// Do not remove!
onAnimate={(from, to) => console.log(from, to)}
>
{data && (
<BottomSheetScrollView style={tw`flex-1 p-4 bg-gray-600`}>
{/* Back Button */}
<Pressable style={tw`w-full ml-4`} onPress={() => fileDetailsRef.current.close()}>
<ChevronLeftIcon color={tw.color('primary-500')} width={20} height={20} />
</Pressable>
{/* File Icon / Name */}
<View style={tw`items-center`}>
<FileIcon file={data} size={1.8} />
<Text style={tw`text-base font-bold text-gray-200 mt-3`}>{data.name}</Text>
</View>
{/* Details */}
<Divider style={tw`mt-6 mb-4`} />
<>
{data?.file?.cas_id && (
<MetaItem title="Unique Content ID" value={data.file.cas_id as string} />
)}
<MetaItem title="URI" value={`/Users/utku/Somewhere/vite.config.js`} />
<Divider style={tw`my-4`} />
<MetaItem
title="Date Created"
value={format(new Date(data.date_created), 'MMMM Do yyyy, h:mm:ss aaa')}
/>
<Divider style={tw`my-4`} />
<MetaItem
title="Date Indexed"
value={format(new Date(data.date_indexed), 'MMMM Do yyyy, h:mm:ss aaa')}
/>
</>
</BottomSheetScrollView>
)}
</BottomSheetModal>
</>
);
};

View file

@ -0,0 +1,13 @@
import { FileModal } from './FileModal';
/*
* Global Modals
* which are mounted when the app starts.
*/
export function GlobalModals() {
return (
<>
<FileModal />
</>
);
}

View file

@ -0,0 +1,10 @@
import { BottomSheetBackdrop, BottomSheetBackdropProps } from '@gorhom/bottom-sheet';
import React from 'react';
const ModalBackdrop = (props: BottomSheetBackdropProps) => {
return (
<BottomSheetBackdrop {...props} appearsOnIndex={0} disappearsOnIndex={-1} opacity={0.75} />
);
};
export default ModalBackdrop;

View file

@ -0,0 +1,16 @@
import { BottomSheetHandle, BottomSheetHandleProps } from '@gorhom/bottom-sheet';
import React from 'react';
import tw from '../../../lib/tailwind';
const ModalHandle = (props: BottomSheetHandleProps) => {
return (
<BottomSheetHandle
{...props}
style={tw`bg-gray-600 rounded-t-xl`}
indicatorStyle={tw`bg-gray-550`}
/>
);
};
export default ModalHandle;

View file

@ -1,4 +1,3 @@
import { Statistics } from '@sd/core';
import byteSize from 'byte-size';
import React from 'react';
import { ScrollView, Text, View } from 'react-native';
@ -6,6 +5,18 @@ import { ScrollView, Text, View } from 'react-native';
import useCounter from '../hooks/useCounter';
import tw from '../lib/tailwind';
interface Statistics {
id: number;
date_captured: string;
total_file_count: number;
library_db_size: string;
total_bytes_used: string;
total_bytes_capacity: string;
total_unique_bytes: string;
total_bytes_free: string;
preview_media_bytes: string;
}
const StatItemNames: Partial<Record<keyof Statistics, string>> = {
total_bytes_capacity: 'Total capacity',
preview_media_bytes: 'Preview media',

View file

@ -0,0 +1,152 @@
import {
ClientTransformer,
OperationKey,
OperationType,
RSPCError,
Transport,
createReactQueryHooks
} from '@rspc/client';
import {
QueryClient,
UseMutationOptions,
UseMutationResult,
UseQueryOptions,
UseQueryResult,
useMutation as _useMutation
} from '@tanstack/react-query';
import { NativeEventEmitter, NativeModules } from 'react-native';
import { useLibraryStore } from '../stores/useLibraryStore';
import type { LibraryArgs, Operations } from '../types/bindings';
export const queryClient = new QueryClient();
export const rspc = createReactQueryHooks<Operations>();
const { SDCore } = NativeModules;
const eventEmitter = new NativeEventEmitter(NativeModules.SDCore);
// TODO(@Oscar): Replace this with a better abstraction when it's released in rspc. This relies on internal details of rspc which will change without warning.
export class ReactNativeTransport implements Transport {
transformer?: ClientTransformer;
clientSubscriptionCallback?: (id: string, key: string, value: any) => void;
constructor() {
const subscriptionEventListener = eventEmitter.addListener('SDCoreEvent', (event) => {
const body = JSON.parse(event);
if (body.type === 'event') {
const { id, key, result } = body;
this.clientSubscriptionCallback(id, key, result);
} else if (body.type === 'response' || body.type === 'error') {
throw new Error(
`Recieved event of type '${body.type}'. This should be impossible with the React Native transport!`
);
} else {
console.error(`Received event of unknown method '${body.type}'`);
}
});
}
async doRequest(operation: OperationType, key: OperationKey): Promise<any> {
const body = JSON.parse(
await SDCore.sd_core_msg(
JSON.stringify({
operation,
key: this.transformer?.serialize(operation, key) || key
})
)
);
if (body.type === 'error') {
const { status_code, message } = body;
throw new RSPCError(status_code, message);
} else if (body.type === 'response') {
return this.transformer?.deserialize(operation, key, body.result) || body.result;
} else if (body.type !== 'none') {
throw new Error(`RSPC ReactNative doRequest received invalid body type '${body?.type}'`);
}
}
}
type NonLibraryQueries = Exclude<Operations['queries'], { key: [any, LibraryArgs<any>] }> &
Extract<Operations['queries'], { key: [any] }>;
type NonLibraryQuery<K extends string> = Extract<NonLibraryQueries, { key: [K] | [K, any] }>;
type NonLibraryQueryKey = NonLibraryQueries['key'][0];
type NonLibraryQueryResult<K extends NonLibraryQueryKey> = NonLibraryQuery<K>['result'];
export function useBridgeQuery<K extends NonLibraryQueries['key']>(
key: K,
options?: UseQueryOptions<NonLibraryQueryResult<K[0]>, RSPCError>
): UseQueryResult<NonLibraryQueryResult<K[0]>, RSPCError> {
// @ts-ignore
return rspc.useQuery(key, options);
}
type LibraryQueries = Extract<Operations['queries'], { key: [string, LibraryArgs<any>] }>;
type LibraryQuery<K extends string> = Extract<LibraryQueries, { key: [K, any] }>;
type LibraryQueryKey = LibraryQueries['key'][0];
type LibraryQueryArgs<K extends string> = LibraryQuery<K>['key'][1] extends LibraryArgs<infer A>
? A
: never;
type LibraryQueryResult<K extends string> = LibraryQuery<K>['result'];
export function useLibraryQuery<K extends LibraryQueryKey>(
key: LibraryQueryArgs<K> extends null | undefined ? [K] : [K, LibraryQueryArgs<K>],
options?: UseQueryOptions<LibraryQueryResult<K>, RSPCError>
): UseQueryResult<LibraryQueryResult<K>, RSPCError> {
const library_id = useLibraryStore((state) => state.currentLibraryUuid);
if (!library_id) throw new Error(`Attempted to do library query with no library set!`);
// @ts-ignore
return rspc.useQuery([key[0], { library_id: library_id || '', arg: key[1] || null }], options);
}
type LibraryMutations = Extract<Operations['mutations'], { key: [string, LibraryArgs<any>] }>;
type LibraryMutation<K extends LibraryMutationKey> = Extract<LibraryMutations, { key: [K, any] }>;
type LibraryMutationKey = LibraryMutations['key'][0];
type LibraryMutationArgs<K extends LibraryMutationKey> =
LibraryMutation<K>['key'][1] extends LibraryArgs<infer A> ? A : never;
type LibraryMutationResult<K extends LibraryMutationKey> = LibraryMutation<K>['result'];
export function useLibraryMutation<K extends LibraryMutationKey>(
key: K,
options?: UseMutationOptions<LibraryMutationResult<K>, RSPCError>
) {
const ctx = rspc.useContext();
const library_id = useLibraryStore((state) => state.currentLibraryUuid);
if (!library_id) throw new Error(`Attempted to do library query with no library set!`);
// @ts-ignore
return _useMutation<LibraryMutationResult<K>, RSPCError, LibraryMutationArgs<K>>(
async (data) => ctx.client.mutation([key, { library_id: library_id || '', arg: data || null }]),
{
...options,
context: rspc.ReactQueryContext
}
);
}
type NonLibraryMutations = Exclude<Operations['mutations'], { key: [any, LibraryArgs<any>] }>;
type NonLibraryMutation<K extends NonLibraryMutationKey> = Extract<
NonLibraryMutations,
{ key: [K] | [K, any] }
>;
type NonLibraryMutationKey = NonLibraryMutations['key'][0];
type NonLibraryMutationArgs<K extends NonLibraryMutationKey> = NonLibraryMutation<K>['key'][1];
type NonLibraryMutationResult<K extends NonLibraryMutationKey> = NonLibraryMutation<K>['result'];
export function useBridgeMutation<K extends NonLibraryMutationKey>(
key: K,
options?: UseMutationOptions<NonLibraryMutationResult<K>, RSPCError>
): UseMutationResult<NonLibraryMutationResult<K>, RSPCError, NonLibraryMutationArgs<K>> {
// @ts-ignore
return rspc.useMutation(key, options);
}
export function useInvalidateQuery() {
const context = rspc.useContext();
rspc.useSubscription(['invalidateQuery'], {
onNext: (invalidateOperation) => {
const key = [invalidateOperation.key];
if (invalidateOperation.arg !== null) {
key.concat(invalidateOperation.arg);
}
context.queryClient.invalidateQueries(key);
}
});
}

View file

@ -1,10 +1,6 @@
import { DrawerScreenProps, createDrawerNavigator } from '@react-navigation/drawer';
import {
CompositeScreenProps,
NavigatorScreenParams,
getFocusedRouteNameFromRoute
} from '@react-navigation/native';
import { NativeStackScreenProps } from '@react-navigation/native-stack';
import { CompositeScreenProps, NavigatorScreenParams } from '@react-navigation/native';
import { StackScreenProps } from '@react-navigation/stack';
import type { RootStackParamList } from '.';
import DrawerContent from '../components/drawer/DrawerContent';
@ -25,8 +21,8 @@ export default function DrawerNavigator() {
width: '75%'
},
overlayColor: 'transparent',
// Can only swipe on Overview screen! (for opening drawer)
swipeEnabled: getFocusedRouteNameFromRoute(route) === 'Overview'
drawerType: 'slide'
// swipeEnabled: false
// drawerHideStatusBarOnOpen: true,
// drawerStatusBarAnimation: 'slide'
};
@ -39,10 +35,10 @@ export default function DrawerNavigator() {
}
export type DrawerNavParamList = {
Home: NavigatorScreenParams<TabParamList> | undefined;
Home: NavigatorScreenParams<TabParamList>;
};
export type HomeDrawerScreenProps<Screen extends keyof DrawerNavParamList> = CompositeScreenProps<
DrawerScreenProps<DrawerNavParamList, Screen>,
NativeStackScreenProps<RootStackParamList, 'Root'>
StackScreenProps<RootStackParamList, 'Root'>
>;

View file

@ -1,8 +1,8 @@
import { NativeStackScreenProps, createNativeStackNavigator } from '@react-navigation/native-stack';
import { StackScreenProps, createStackNavigator } from '@react-navigation/stack';
import OnboardingScreen from '../screens/onboarding/Onboarding';
const OnboardingStack = createNativeStackNavigator<OnboardingStackParamList>();
const OnboardingStack = createStackNavigator<OnboardingStackParamList>();
export default function OnboardingNavigator() {
return (
@ -17,4 +17,4 @@ export type OnboardingStackParamList = {
};
export type OnboardingStackScreenProps<Screen extends keyof OnboardingStackParamList> =
NativeStackScreenProps<OnboardingStackParamList, Screen>;
StackScreenProps<OnboardingStackParamList, Screen>;

View file

@ -0,0 +1,36 @@
import { ParamListBase, StackNavigationState, TypedNavigator } from '@react-navigation/native';
import {
StackNavigationEventMap,
StackNavigationOptions,
StackScreenProps
} from '@react-navigation/stack';
import LocationScreen from '../screens/Location';
import TagScreen from '../screens/Tag';
export function SharedScreens(
Stack: TypedNavigator<
SharedScreensParamList,
StackNavigationState<ParamListBase>,
StackNavigationOptions,
StackNavigationEventMap,
any
>
) {
return (
<>
<Stack.Screen name="Location" component={LocationScreen} />
<Stack.Screen name="Tag" component={TagScreen} />
</>
);
}
export type SharedScreensParamList = {
Location: { id: number };
Tag: { id: number };
};
export type SharedScreenProps<Screen extends keyof SharedScreensParamList> = StackScreenProps<
SharedScreensParamList,
Screen
>;

View file

@ -1,21 +1,21 @@
import { BottomTabScreenProps, createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { CompositeScreenProps } from '@react-navigation/native';
import { CompositeScreenProps, NavigatorScreenParams } from '@react-navigation/native';
import { CirclesFour, Folder, Planet } from 'phosphor-react-native';
import { PhotographIcon } from 'react-native-heroicons/outline';
import tw from '../lib/tailwind';
import OverviewScreen from '../screens/Overview';
import PhotosScreen from '../screens/Photos';
import SpacesScreen from '../screens/Spaces';
import type { HomeDrawerScreenProps } from './DrawerNavigator';
import BrowseStack from './tabs/BrowseStack';
import BrowseStack, { BrowseStackParamList } from './tabs/BrowseStack';
import OverviewStack, { OverviewStackParamList } from './tabs/OverviewStack';
import PhotosStack, { PhotosStackParamList } from './tabs/PhotosStack';
import SpacesStack, { SpacesStackParamList } from './tabs/SpacesStack';
const Tab = createBottomTabNavigator<TabParamList>();
export default function TabNavigator() {
return (
<Tab.Navigator
initialRouteName="Overview"
initialRouteName="OverviewStack"
screenOptions={{
headerShown: false,
tabBarActiveTintColor: tw.color('bg-primary'),
@ -27,12 +27,13 @@ export default function TabNavigator() {
}}
>
<Tab.Screen
name="Overview"
component={OverviewScreen}
name="OverviewStack"
component={OverviewStack}
options={{
tabBarIcon: ({ focused }) => (
<Planet size={22} weight="bold" color={focused ? tw.color('bg-primary') : 'white'} />
)
),
tabBarLabel: 'Overview'
}}
/>
<Tab.Screen
@ -46,8 +47,8 @@ export default function TabNavigator() {
}}
/>
<Tab.Screen
name="Spaces"
component={SpacesScreen}
name="SpacesStack"
component={SpacesStack}
options={{
tabBarIcon: ({ focused }) => (
<CirclesFour
@ -55,16 +56,18 @@ export default function TabNavigator() {
weight="bold"
color={focused ? tw.color('bg-primary') : 'white'}
/>
)
),
tabBarLabel: 'Spaces'
}}
/>
<Tab.Screen
name="Photos"
component={PhotosScreen}
name="PhotosStack"
component={PhotosStack}
options={{
tabBarIcon: ({ focused }) => (
<PhotographIcon size={22} color={focused ? tw.color('bg-primary') : 'white'} />
)
),
tabBarLabel: 'Photos'
}}
/>
</Tab.Navigator>
@ -72,10 +75,10 @@ export default function TabNavigator() {
}
export type TabParamList = {
Overview: undefined;
BrowseStack: undefined;
Spaces: undefined;
Photos: undefined;
OverviewStack: NavigatorScreenParams<OverviewStackParamList>;
BrowseStack: NavigatorScreenParams<BrowseStackParamList>;
SpacesStack: NavigatorScreenParams<SpacesStackParamList>;
PhotosStack: NavigatorScreenParams<PhotosStackParamList>;
};
export type TabScreenProps<Screen extends keyof TabParamList> = CompositeScreenProps<

View file

@ -1,12 +1,13 @@
import { NavigatorScreenParams } from '@react-navigation/native';
import { NativeStackScreenProps, createNativeStackNavigator } from '@react-navigation/native-stack';
import { StackScreenProps, createStackNavigator } from '@react-navigation/stack';
import NotFoundScreen from '../screens/NotFound';
import SearchScreen from '../screens/modals/Search';
import SettingsScreen from '../screens/modals/settings/Settings';
import DrawerNavigator from './DrawerNavigator';
import type { DrawerNavParamList } from './DrawerNavigator';
import DrawerNavigator from './DrawerNavigator';
const Stack = createNativeStackNavigator<RootStackParamList>();
const Stack = createStackNavigator<RootStackParamList>();
// This is the main navigator we nest everything under.
export default function RootNavigator() {
@ -14,7 +15,17 @@ export default function RootNavigator() {
<Stack.Navigator initialRouteName="Root">
<Stack.Screen name="Root" component={DrawerNavigator} options={{ headerShown: false }} />
<Stack.Screen name="NotFound" component={NotFoundScreen} options={{ title: 'Oops!' }} />
<Stack.Group screenOptions={{ presentation: 'modal' }}>
<Stack.Screen name="Search" component={SearchScreen} options={{ headerShown: false }} />
{/* Modals */}
<Stack.Group
screenOptions={{
presentation: 'modal',
headerBackTitleVisible: false,
headerStyle: { backgroundColor: '#08090D' },
// headerShadowVisible: false,
headerTintColor: '#fff'
}}
>
<Stack.Screen name="Settings" component={SettingsScreen} />
</Stack.Group>
</Stack.Navigator>
@ -22,13 +33,23 @@ export default function RootNavigator() {
}
export type RootStackParamList = {
Root: NavigatorScreenParams<DrawerNavParamList> | undefined;
Root: NavigatorScreenParams<DrawerNavParamList>;
NotFound: undefined;
// Modals
Search: undefined;
Settings: undefined;
};
export type RootStackScreenProps<Screen extends keyof RootStackParamList> = NativeStackScreenProps<
export type RootStackScreenProps<Screen extends keyof RootStackParamList> = StackScreenProps<
RootStackParamList,
Screen
>;
// This declaration is used by useNavigation, Link, ref etc.
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace ReactNavigation {
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface RootParamList extends RootStackParamList {}
}
}

View file

@ -1,30 +1,35 @@
import { CompositeScreenProps } from '@react-navigation/native';
import { NativeStackScreenProps, createNativeStackNavigator } from '@react-navigation/native-stack';
import { StackScreenProps, TransitionPresets, createStackNavigator } from '@react-navigation/stack';
import Header from '../../components/header/Header';
import BrowseScreen from '../../screens/Browse';
import LocationScreen from '../../screens/Location';
import TagScreen from '../../screens/Tag';
import { SharedScreens, SharedScreensParamList } from '../SharedScreens';
import { TabScreenProps } from '../TabNavigator';
const Stack = createNativeStackNavigator<BrowseStackParamList>();
const Stack = createStackNavigator<BrowseStackParamList>();
export default function BrowseStack() {
return (
<Stack.Navigator initialRouteName="Browse">
<Stack.Screen name="Browse" component={BrowseScreen} />
<Stack.Screen name="Location" component={LocationScreen} />
<Stack.Screen name="Tag" component={TagScreen} />
<Stack.Navigator
initialRouteName="Browse"
screenOptions={{
headerStyle: { backgroundColor: '#08090D' },
headerTintColor: '#fff',
...TransitionPresets.ModalFadeTransition
}}
>
<Stack.Screen name="Browse" component={BrowseScreen} options={{ header: Header }} />
{SharedScreens(Stack as any)}
</Stack.Navigator>
);
}
export type BrowseStackParamList = {
Browse: undefined;
Location: { id: number };
Tag: { id: number };
};
} & SharedScreensParamList;
export type BrowseScreenProps<Screen extends keyof BrowseStackParamList> = CompositeScreenProps<
NativeStackScreenProps<BrowseStackParamList, Screen>,
TabScreenProps<'BrowseStack'>
>;
export type BrowseStackScreenProps<Screen extends keyof BrowseStackParamList> =
CompositeScreenProps<
StackScreenProps<BrowseStackParamList, Screen>,
TabScreenProps<'BrowseStack'>
>;

View file

@ -0,0 +1,35 @@
import { CompositeScreenProps } from '@react-navigation/native';
import { StackScreenProps, TransitionPresets, createStackNavigator } from '@react-navigation/stack';
import Header from '../../components/header/Header';
import OverviewScreen from '../../screens/Overview';
import { SharedScreens, SharedScreensParamList } from '../SharedScreens';
import { TabScreenProps } from '../TabNavigator';
const Stack = createStackNavigator<OverviewStackParamList>();
export default function OverviewStack() {
return (
<Stack.Navigator
initialRouteName="Overview"
screenOptions={{
headerStyle: { backgroundColor: '#08090D' },
headerTintColor: '#fff',
...TransitionPresets.ModalFadeTransition
}}
>
<Stack.Screen name="Overview" component={OverviewScreen} options={{ header: Header }} />
{SharedScreens(Stack as any)}
</Stack.Navigator>
);
}
export type OverviewStackParamList = {
Overview: undefined;
} & SharedScreensParamList;
export type OverviewStackScreenProps<Screen extends keyof OverviewStackParamList> =
CompositeScreenProps<
StackScreenProps<OverviewStackParamList, Screen>,
TabScreenProps<'OverviewStack'>
>;

View file

@ -0,0 +1,35 @@
import { CompositeScreenProps } from '@react-navigation/native';
import { StackScreenProps, TransitionPresets, createStackNavigator } from '@react-navigation/stack';
import Header from '../../components/header/Header';
import PhotosScreen from '../../screens/Photos';
import { SharedScreens, SharedScreensParamList } from '../SharedScreens';
import { TabScreenProps } from '../TabNavigator';
const Stack = createStackNavigator<PhotosStackParamList>();
export default function PhotosStack() {
return (
<Stack.Navigator
initialRouteName="Photos"
screenOptions={{
headerStyle: { backgroundColor: '#08090D' },
headerTintColor: '#fff',
...TransitionPresets.ModalFadeTransition
}}
>
<Stack.Screen name="Photos" component={PhotosScreen} options={{ header: Header }} />
{SharedScreens(Stack as any)}
</Stack.Navigator>
);
}
export type PhotosStackParamList = {
Photos: undefined;
} & SharedScreensParamList;
export type PhotosStackScreenProps<Screen extends keyof PhotosStackParamList> =
CompositeScreenProps<
StackScreenProps<PhotosStackParamList, Screen>,
TabScreenProps<'PhotosStack'>
>;

View file

@ -0,0 +1,35 @@
import { CompositeScreenProps } from '@react-navigation/native';
import { StackScreenProps, TransitionPresets, createStackNavigator } from '@react-navigation/stack';
import Header from '../../components/header/Header';
import SpacesScreen from '../../screens/Spaces';
import { SharedScreens, SharedScreensParamList } from '../SharedScreens';
import { TabScreenProps } from '../TabNavigator';
const Stack = createStackNavigator<SpacesStackParamList>();
export default function SpacesStack() {
return (
<Stack.Navigator
initialRouteName="Spaces"
screenOptions={{
headerStyle: { backgroundColor: '#08090D' },
headerTintColor: '#fff',
...TransitionPresets.ModalFadeTransition
}}
>
<Stack.Screen name="Spaces" component={SpacesScreen} options={{ header: Header }} />
{SharedScreens(Stack as any)}
</Stack.Navigator>
);
}
export type SpacesStackParamList = {
Spaces: undefined;
} & SharedScreensParamList;
export type SpacesStackScreenProps<Screen extends keyof SpacesStackParamList> =
CompositeScreenProps<
StackScreenProps<SpacesStackParamList, Screen>,
TabScreenProps<'SpacesStack'>
>;

View file

@ -5,7 +5,7 @@ import BrowseLocationItem from '../components/browse/BrowseLocationItem';
import BrowseTagItem from '../components/browse/BrowseTagItem';
import CollapsibleView from '../components/layout/CollapsibleView';
import tw from '../lib/tailwind';
import { BrowseScreenProps } from '../navigation/tabs/BrowseStack';
import { BrowseStackScreenProps } from '../navigation/tabs/BrowseStack';
const placeholderLocationData = [
{
@ -35,7 +35,7 @@ const placeholderTagsData = [
}
];
const BrowseScreen = ({ navigation }: BrowseScreenProps<'Browse'>) => {
const BrowseScreen = ({ navigation }: BrowseStackScreenProps<'Browse'>) => {
return (
<View style={tw`flex-1 p-4`}>
<CollapsibleView

View file

@ -2,8 +2,9 @@ import React from 'react';
import { Text, View } from 'react-native';
import tw from '../lib/tailwind';
import { SharedScreenProps } from '../navigation/SharedScreens';
export default function LocationScreen({ navigation, route }: any) {
export default function LocationScreen({ navigation, route }: SharedScreenProps<'Location'>) {
const { id } = route.params;
return (
<View style={tw`flex-1 items-center justify-center`}>

View file

@ -1,13 +1,11 @@
import React from 'react';
import { FlatList, Text, View } from 'react-native';
import { FlatList, View } from 'react-native';
import { Button } from '../components/base/Button';
import Device from '../components/device/Device';
import DrawerScreenWrapper from '../components/drawer/DrawerScreenWrapper';
import VirtualizedListWrapper from '../components/layout/VirtualizedListWrapper';
import OverviewStats from '../containers/OverviewStats';
import tw from '../lib/tailwind';
import type { TabScreenProps } from '../navigation/TabNavigator';
import { OverviewStackScreenProps } from '../navigation/tabs/OverviewStack';
const placeholderOverviewStats = {
id: 1,
@ -48,31 +46,23 @@ const placeholderDevices: any = [
}
];
export default function OverviewScreen({ navigation }: TabScreenProps<'Overview'>) {
export default function OverviewScreen({ navigation }: OverviewStackScreenProps<'Overview'>) {
return (
<DrawerScreenWrapper>
<VirtualizedListWrapper>
<View style={tw`px-4`}>
{/* Header */}
<View style={tw`flex-row my-6 justify-center items-center`}>
{/* TODO: Header with a button to open drawer! */}
<Button variant="primary" size="lg" onPress={() => navigation.openDrawer()}>
<Text style={tw`font-bold text-white`}>Open Drawer</Text>
</Button>
</View>
{/* Stats */}
<OverviewStats stats={placeholderOverviewStats} />
<View style={tw`mt-4`} />
{/* Devices */}
<FlatList
data={placeholderDevices}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => (
<Device locations={[]} name={item.name} size={item.size} type={item.type} />
)}
/>
</View>
</VirtualizedListWrapper>
</DrawerScreenWrapper>
<VirtualizedListWrapper>
<View style={tw`px-4 mt-4`}>
{/* Stats */}
<OverviewStats stats={placeholderOverviewStats} />
{/* Spacing */}
<View style={tw`mt-4`} />
{/* Devices */}
<FlatList
data={placeholderDevices}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => (
<Device locations={[]} name={item.name} size={item.size} type={item.type} />
)}
/>
</View>
</VirtualizedListWrapper>
);
}

View file

@ -2,9 +2,9 @@ import React from 'react';
import { Text, View } from 'react-native';
import tw from '../lib/tailwind';
import type { TabScreenProps } from '../navigation/TabNavigator';
import { PhotosStackScreenProps } from '../navigation/tabs/PhotosStack';
export default function PhotosScreen({ navigation }: TabScreenProps<'Photos'>) {
export default function PhotosScreen({ navigation }: PhotosStackScreenProps<'Photos'>) {
return (
<View style={tw`flex-1 items-center justify-center`}>
<Text style={tw`font-bold text-xl text-white`}>Photos</Text>

View file

@ -1,14 +1,13 @@
import React from 'react';
import { Text } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { Text, View } from 'react-native';
import tw from '../lib/tailwind';
import type { TabScreenProps } from '../navigation/TabNavigator';
import { SpacesStackScreenProps } from '../navigation/tabs/SpacesStack';
export default function SpacesScreen({ navigation }: TabScreenProps<'Spaces'>) {
export default function SpacesScreen({ navigation }: SpacesStackScreenProps<'Spaces'>) {
return (
<SafeAreaView style={tw`flex-1 items-center justify-center`}>
<View style={tw`flex-1 items-center justify-center`}>
<Text style={tw`font-bold text-xl text-white`}>Spaces</Text>
</SafeAreaView>
</View>
);
}

View file

@ -2,8 +2,9 @@ import React from 'react';
import { Text, View } from 'react-native';
import tw from '../lib/tailwind';
import { SharedScreenProps } from '../navigation/SharedScreens';
export default function TagScreen({ navigation, route }: any) {
export default function TagScreen({ navigation, route }: SharedScreenProps<'Tag'>) {
const { id } = route.params;
return (
<View style={tw`flex-1 items-center justify-center`}>

View file

@ -0,0 +1,57 @@
import { MagnifyingGlass } from 'phosphor-react-native';
import React, { useState } from 'react';
import { ActivityIndicator, Pressable, Text, TextInput, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { Button } from '../../components/base/Button';
import tw from '../../lib/tailwind';
import { RootStackScreenProps } from '../../navigation';
const SearchScreen = ({ navigation }: RootStackScreenProps<'Search'>) => {
const { top } = useSafeAreaInsets();
const [loading, setLoading] = useState(false);
return (
<View style={tw.style('flex-1', { marginTop: top + 10 })}>
{/* Header */}
<View style={tw`flex flex-row items-center mx-4`}>
{/* Search Input */}
<View style={tw`flex-1 bg-gray-550 rounded-md h-9 mr-3`}>
<View style={tw`flex flex-row h-full items-center px-3`}>
<View style={tw`mr-3`}>
{loading ? (
<ActivityIndicator size={'small'} color={'white'} />
) : (
<MagnifyingGlass size={20} weight="light" color={tw.color('gray-300')} />
)}
</View>
<TextInput
placeholder={'Search'}
clearButtonMode="never" // can't change the color??
underlineColorAndroid="transparent"
placeholderTextColor={tw.color('gray-300')}
style={tw`text-white flex-1 text-sm`}
textContentType={'none'}
autoFocus
autoCapitalize="none"
autoCorrect={false}
/>
</View>
</View>
{/* Cancel Button */}
<Pressable onPress={() => navigation.goBack()}>
<Text style={tw`text-primary-500`}>Cancel</Text>
</Pressable>
</View>
{/* Content */}
<View style={tw`flex-1 items-center mt-8`}>
<Button variant="primary" onPress={() => setLoading((v) => !v)}>
<Text>Toggle loading</Text>
</Button>
</View>
</View>
);
};
export default SearchScreen;

View file

@ -6,7 +6,7 @@ import { RootStackScreenProps } from '../../../navigation';
export default function SettingsScreen({ navigation }: RootStackScreenProps<'Settings'>) {
return (
<View style={tw`flex-1`}>
<View style={tw`flex-1 items-center justify-center`}>
<Text style={tw`font-bold text-xl text-white`}>Settings</Text>
<View style={tw`my-8 h-1 w-4/5`} />
</View>

View file

@ -12,10 +12,6 @@ const OnboardingScreen = ({ navigation }: OnboardingStackScreenProps<'Onboarding
const { hideOnboarding } = useOnboardingStore();
function onButtonPress() {
// Persist onboarding state only when app in production for now.
// if (process.env.NODE_ENV === 'production') {
// setItemToStorage('@onboarding', '1');
// }
setItemToStorage('@onboarding', '1');
// TODO: Add a loading indicator to button as this takes a second or so.
hideOnboarding();
@ -26,8 +22,7 @@ const OnboardingScreen = ({ navigation }: OnboardingStackScreenProps<'Onboarding
{/* Logo */}
<LogoAnimation>
<View style={tw`items-center mt-2`}>
{/* TODO: Change this to @sd/assets. */}
<Image source={require('../../assets/temp/logo.png')} style={tw`w-24 h-24`} />
<Image source={require('@sd/assets/images/logo.png')} style={tw`w-24 h-24`} />
</View>
</LogoAnimation>
{/* Text */}

View file

@ -0,0 +1,13 @@
import create from 'zustand';
interface LibraryStore {
currentLibraryUuid: string | null;
switchLibrary: (id: string) => void;
}
export const useLibraryStore = create<LibraryStore>()((set) => ({
currentLibraryUuid: null,
switchLibrary: (uuid) => {
set((state) => ({ currentLibraryUuid: uuid }));
}
}));

View file

@ -0,0 +1,19 @@
import { BottomSheetModal } from '@gorhom/bottom-sheet';
import React from 'react';
import create from 'zustand';
import { FilePath } from '../types/bindings';
interface FileModalState {
fileRef: React.RefObject<BottomSheetModal>;
data: FilePath | null;
setData: (data: FilePath) => void;
clearData: () => void;
}
export const useFileModalStore = create<FileModalState>((set) => ({
fileRef: React.createRef<BottomSheetModal>(),
data: null,
setData: (data: FilePath) => set((_) => ({ data })),
clearData: () => set((_) => ({ data: null }))
}));

View file

@ -0,0 +1,117 @@
// This file was generated by [rspc](https://github.com/oscartbeaumont/rspc). Do not edit this file manually.
export type Operations = {
queries:
{ key: ["files.readMetadata", LibraryArgs<number>], result: null } |
{ key: ["jobs.getHistory", LibraryArgs<null>], result: Array<JobReport> } |
{ key: ["jobs.getRunning", LibraryArgs<null>], result: Array<JobReport> } |
{ key: ["library.get"], result: Array<LibraryConfigWrapped> } |
{ key: ["locations.getExplorerDir", LibraryArgs<GetExplorerDirArgs>], result: DirectoryWithContents } |
{ key: ["locations.getById", LibraryArgs<number>], result: Location | null } |
{ key: ["getNode"], result: NodeState } |
{ key: ["version"], result: string } |
{ key: ["volumes.get"], result: Array<Volume> } |
{ key: ["tags.getFilesForTag", LibraryArgs<number>], result: Tag | null } |
{ key: ["tags.get", LibraryArgs<null>], result: Array<Tag> } |
{ key: ["library.getStatistics", LibraryArgs<null>], result: Statistics } |
{ key: ["locations.get", LibraryArgs<null>], result: Array<Location> },
mutations:
{ key: ["jobs.generateThumbsForLocation", LibraryArgs<GenerateThumbsForLocationArgs>], result: null } |
{ key: ["files.setNote", LibraryArgs<SetNoteArgs>], result: null } |
{ key: ["library.create", string], result: null } |
{ key: ["library.delete", string], result: null } |
{ key: ["files.setFavorite", LibraryArgs<SetFavoriteArgs>], result: null } |
{ key: ["locations.update", LibraryArgs<LocationUpdateArgs>], result: null } |
{ key: ["tags.update", LibraryArgs<TagUpdateArgs>], result: null } |
{ key: ["tags.assign", LibraryArgs<TagAssignArgs>], result: null } |
{ key: ["tags.delete", LibraryArgs<number>], result: null } |
{ key: ["library.edit", EditLibraryArgs], result: null } |
{ key: ["jobs.identifyUniqueFiles", LibraryArgs<IdentifyUniqueFilesArgs>], result: null } |
{ key: ["locations.create", LibraryArgs<string>], result: Location } |
{ key: ["locations.quickRescan", LibraryArgs<null>], result: null } |
{ key: ["files.delete", LibraryArgs<number>], result: null } |
{ key: ["locations.delete", LibraryArgs<number>], result: null } |
{ key: ["locations.fullRescan", LibraryArgs<number>], result: null } |
{ key: ["tags.create", LibraryArgs<TagCreateArgs>], result: Tag },
subscriptions:
{ key: ["jobs.newThumbnail", LibraryArgs<null>], result: string } |
{ key: ["invalidateQuery"], result: InvalidateOperationEvent }
};
export interface GenerateThumbsForLocationArgs { id: number, path: string }
export interface SyncEvent { id: number, node_id: number, timestamp: string, record_id: Array<number>, kind: number, column: string | null, value: string, node: Node | null }
export interface Location { id: number, pub_id: Array<number>, node_id: number | null, name: string | null, local_path: string | null, total_capacity: number | null, available_capacity: number | null, filesystem: string | null, disk_type: number | null, is_removable: boolean | null, is_online: boolean, date_created: string, node: Node | null | null, file_paths: Array<FilePath> | null }
export interface TagAssignArgs { file_id: number, tag_id: number }
export interface Key { id: number, checksum: string, name: string | null, date_created: string | null, algorithm: number | null, files: Array<File> | null, file_paths: Array<FilePath> | null }
export interface DirectoryWithContents { directory: FilePath, contents: Array<FilePath> }
export interface ConfigMetadata { version: string | null }
export interface TagUpdateArgs { id: number, name: string | null, color: string | null }
export interface LibraryConfig { version: string | null, name: string, description: string }
export interface IdentifyUniqueFilesArgs { id: number, path: string }
export interface FilePath { id: number, is_dir: boolean, location_id: number | null, materialized_path: string, name: string, extension: string | null, file_id: number | null, parent_id: number | null, key_id: number | null, date_created: string, date_modified: string, date_indexed: string, file: File | null | null, location: Location | null | null, key: Key | null | null }
export interface Album { id: number, pub_id: Array<number>, name: string, is_hidden: boolean, date_created: string, date_modified: string, files: Array<FileInAlbum> | null }
export interface SetFavoriteArgs { id: number, favorite: boolean }
export interface LocationUpdateArgs { id: number, name: string | null }
export interface Job { id: Array<number>, name: string, node_id: number, action: number, status: number, data: Array<number> | null, task_count: number, completed_task_count: number, date_created: string, date_modified: string, seconds_elapsed: number, nodes: Node | null }
export interface Statistics { id: number, date_captured: string, total_file_count: number, library_db_size: string, total_bytes_used: string, total_bytes_capacity: string, total_unique_bytes: string, total_bytes_free: string, preview_media_bytes: string }
export interface MediaData { id: number, pixel_width: number | null, pixel_height: number | null, longitude: number | null, latitude: number | null, fps: number | null, capture_device_make: string | null, capture_device_model: string | null, capture_device_software: string | null, duration_seconds: number | null, codecs: string | null, streams: number | null, files: File | null | null }
export interface NodeConfig { version: string | null, id: string, name: string, p2p_port: number | null }
export interface TagCreateArgs { name: string, color: string }
export interface FileInAlbum { date_created: string, album_id: number, album: Album | null, file_id: number, file: File | null }
export interface Label { id: number, pub_id: Array<number>, name: string | null, date_created: string, date_modified: string, label_files: Array<LabelOnFile> | null }
export interface LabelOnFile { date_created: string, label_id: number, label: Label | null, file_id: number, file: File | null }
export interface EditLibraryArgs { id: string, name: string | null, description: string | null }
export interface Space { id: number, pub_id: Array<number>, name: string | null, description: string | null, date_created: string, date_modified: string, files: Array<FileInSpace> | null }
export interface Comment { id: number, pub_id: Array<number>, content: string, date_created: string, date_modified: string, file_id: number | null, file: File | null | null }
export interface GetExplorerDirArgs { location_id: number, path: string, limit: number }
export type JobStatus = "Queued" | "Running" | "Completed" | "Canceled" | "Failed" | "Paused"
export interface JobReport { id: string, name: string, data: Array<number> | null, date_created: string, date_modified: string, status: JobStatus, task_count: number, completed_task_count: number, message: string, seconds_elapsed: number }
export interface Tag { id: number, pub_id: Array<number>, name: string | null, color: string | null, total_files: number | null, redundancy_goal: number | null, date_created: string, date_modified: string, tag_files: Array<TagOnFile> | null }
export interface LibraryConfigWrapped { uuid: string, config: LibraryConfig }
export interface FileInSpace { date_created: string, space_id: number, space: Space | null, file_id: number, file: File | null }
export interface InvalidateOperationEvent { key: string, arg: any }
export interface TagOnFile { date_created: string, tag_id: number, tag: Tag | null, file_id: number, file: File | null }
export interface NodeState { version: string | null, id: string, name: string, p2p_port: number | null, data_path: string }
export interface LibraryArgs<T> { library_id: string, arg: T }
export interface Node { id: number, pub_id: Array<number>, name: string, platform: number, version: string | null, last_seen: string, timezone: string | null, date_created: string, sync_events: Array<SyncEvent> | null, jobs: Array<Job> | null, Location: Array<Location> | null }
export interface File { id: number, cas_id: string, integrity_checksum: string | null, kind: number, size_in_bytes: string, key_id: number | null, hidden: boolean, favorite: boolean, important: boolean, has_thumbnail: boolean, has_thumbstrip: boolean, has_video_preview: boolean, ipfs_id: string | null, note: string | null, date_created: string, date_modified: string, date_indexed: string, tags: Array<TagOnFile> | null, labels: Array<LabelOnFile> | null, albums: Array<FileInAlbum> | null, spaces: Array<FileInSpace> | null, paths: Array<FilePath> | null, comments: Array<Comment> | null, media_data: MediaData | null | null, key: Key | null | null }
export interface Volume { name: string, mount_point: string, total_capacity: bigint, available_capacity: bigint, is_removable: boolean, disk_type: string | null, file_system: string | null, is_root_filesystem: boolean }
export interface SetNoteArgs { id: number, note: string | null }

View file

@ -4,11 +4,3 @@ declare module '*.svg' {
const content: React.FC<SvgProps>;
export default content;
}
// This declaration is used by useNavigation, Link, ref etc.
declare global {
namespace ReactNavigation {
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface RootParamList extends RootStackParamList {}
}
}

View file

@ -5,6 +5,7 @@ edition = "2021"
[dependencies]
sdcore = { path = "../../core", features = [] }
rspc = { version = "0.0.4", features = ["axum"] }
axum = "0.5.13"
tokio = { version = "1.17.0", features = ["sync", "rt-multi-thread", "signal"] }
tracing = "0.1.35"

View file

@ -6,10 +6,13 @@ authors = ["Spacedrive Technology Inc."]
license = "GNU GENERAL PUBLIC LICENSE"
repository = "https://github.com/spacedriveapp/spacedrive"
edition = "2021"
rust-version = "1.63.0"
[features]
p2p = [
] # This feature controlls whether the Spacedrive Core contains the Peer to Peer syncing engine (It isn't required for the hosted core so we can disable it).
default = ["p2p"]
p2p = [] # This feature controlls whether the Spacedrive Core contains the Peer to Peer syncing engine (It isn't required for the hosted core so we can disable it).
mobile = [] # This feature allows features to be disabled when the Core is running on mobile.
ffmpeg = ["dep:ffmpeg-next"] # This feature controls whether the Spacedrive Core contains functionality which requires FFmpeg.
[dependencies]
hostname = "0.3.1"
@ -32,8 +35,6 @@ prisma-client-rust = { git = "https://github.com/Brendonovich/prisma-client-rust
"sqlite-create-many",
] }
rspc = { version = "0.0.4", features = [
"axum",
"tauri",
"uuid",
"chrono",
"tracing",
@ -42,14 +43,13 @@ walkdir = "^2.3.2"
uuid = { version = "1.1.2", features = ["v4", "serde"] }
sysinfo = "0.23.9"
thiserror = "1.0.30"
core-derive = { path = "./derive" }
tokio = { version = "1.17.0", features = ["sync", "rt-multi-thread"] }
include_dir = { version = "0.7.2", features = ["glob"] }
async-trait = "^0.1.52"
image = "0.24.1"
webp = "0.2.2"
ffmpeg-next = "5.0.3"
ffmpeg-next = { version = "5.0.3", optional = true, features = [] }
fs_extra = "1.2.0"
tracing = "0.1.35"
tracing-subscriber = { version = "0.3.14", features = ["env-filter"] }

View file

@ -1,11 +0,0 @@
[package]
name = "core-derive"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
[dependencies]
quote = "1.0.18"
syn = "1.0.91"

View file

@ -1,42 +0,0 @@
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput};
/// This macro must be executed in a file with `PropertyOperationCtx` defined and in the same package as the SyncContext is defined.
/// The creates:
/// ```rust
/// impl PropertyOperation {
/// fn apply(operation: PropertyOperationCtx, ctx: SyncContext) {
/// match operation.resource {
/// PropertyOperation::Tag(method) => method.apply(ctx),
/// };
/// }
/// }
/// ```
#[proc_macro_derive(PropertyOperationApply)]
pub fn property_operation_apply(input: TokenStream) -> TokenStream {
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
if let Data::Enum(data) = data {
let impls = data.variants.iter().map(|variant| {
let variant_ident = &variant.ident;
quote! {
#ident::#variant_ident(method) => method.apply(ctx),
}
});
let expanded = quote! {
impl #ident {
fn apply(operation: CrdtCtx<PropertyOperation>, ctx: self::engine::SyncContext) {
match operation.resource {
#(#impls)*
};
}
}
};
TokenStream::from(expanded)
} else {
panic!("The 'PropertyOperationApply' macro can only be used on enums!");
}
}

View file

@ -1,118 +1,117 @@
/* eslint-disable */
// This file was generated by [rspc](https://github.com/oscartbeaumont/rspc). Do not edit this file manually.
export type Operations = {
queries:
{ key: ["getNode"], result: NodeState } |
{ key: ["version"], result: string } |
{ key: ["tags.getFilesForTag", LibraryArgs<number>], result: Tag | null } |
{ key: ["locations.getById", LibraryArgs<number>], result: Location | null } |
{ key: ["files.readMetadata", LibraryArgs<number>], result: null } |
{ key: ["locations.get", LibraryArgs<null>], result: Array<Location> } |
{ key: ["jobs.getHistory", LibraryArgs<null>], result: Array<JobReport> } |
{ key: ["jobs.getRunning", LibraryArgs<null>], result: Array<JobReport> } |
{ key: ["library.get"], result: Array<LibraryConfigWrapped> } |
{ key: ["locations.getExplorerDir", LibraryArgs<GetExplorerDirArgs>], result: DirectoryWithContents } |
{ key: ["locations.getById", LibraryArgs<number>], result: Location | null } |
{ key: ["getNode"], result: NodeState } |
{ key: ["version"], result: string } |
{ key: ["volumes.get"], result: Array<Volume> } |
{ key: ["tags.getFilesForTag", LibraryArgs<number>], result: Tag | null } |
{ key: ["tags.get", LibraryArgs<null>], result: Array<Tag> } |
{ key: ["jobs.getHistory", LibraryArgs<null>], result: Array<JobReport> } |
{ key: ["library.getStatistics", LibraryArgs<null>], result: Statistics } |
{ key: ["volumes.get"], result: Array<Volume> },
{ key: ["locations.get", LibraryArgs<null>], result: Array<Location> },
mutations:
{ key: ["jobs.generateThumbsForLocation", LibraryArgs<GenerateThumbsForLocationArgs>], result: null } |
{ key: ["files.setNote", LibraryArgs<SetNoteArgs>], result: null } |
{ key: ["library.create", string], result: null } |
{ key: ["library.delete", string], result: null } |
{ key: ["files.setFavorite", LibraryArgs<SetFavoriteArgs>], result: null } |
{ key: ["tags.assign", LibraryArgs<TagAssignArgs>], result: null } |
{ key: ["locations.update", LibraryArgs<LocationUpdateArgs>], result: null } |
{ key: ["tags.update", LibraryArgs<TagUpdateArgs>], result: null } |
{ key: ["tags.assign", LibraryArgs<TagAssignArgs>], result: null } |
{ key: ["tags.delete", LibraryArgs<number>], result: null } |
{ key: ["library.edit", EditLibraryArgs], result: null } |
{ key: ["jobs.identifyUniqueFiles", LibraryArgs<IdentifyUniqueFilesArgs>], result: null } |
{ key: ["locations.create", LibraryArgs<string>], result: Location } |
{ key: ["locations.quickRescan", LibraryArgs<null>], result: null } |
{ key: ["files.delete", LibraryArgs<number>], result: null } |
{ key: ["locations.delete", LibraryArgs<number>], result: null } |
{ key: ["locations.fullRescan", LibraryArgs<number>], result: null } |
{ key: ["tags.delete", LibraryArgs<number>], result: null } |
{ key: ["jobs.identifyUniqueFiles", LibraryArgs<IdentifyUniqueFilesArgs>], result: null } |
{ key: ["library.delete", string], result: null } |
{ key: ["files.delete", LibraryArgs<number>], result: null } |
{ key: ["locations.quickRescan", LibraryArgs<null>], result: null } |
{ key: ["locations.create", LibraryArgs<string>], result: Location } |
{ key: ["files.setNote", LibraryArgs<SetNoteArgs>], result: null } |
{ key: ["library.edit", EditLibraryArgs], result: null } |
{ key: ["tags.create", LibraryArgs<TagCreateArgs>], result: Tag } |
{ key: ["library.create", string], result: null } |
{ key: ["jobs.generateThumbsForLocation", LibraryArgs<GenerateThumbsForLocationArgs>], result: null } |
{ key: ["tags.update", LibraryArgs<TagUpdateArgs>], result: null },
{ key: ["tags.create", LibraryArgs<TagCreateArgs>], result: Tag },
subscriptions:
{ key: ["jobs.newThumbnail", LibraryArgs<null>], result: string } |
{ key: ["invalidateQuery"], result: InvalidateOperationEvent }
};
export interface Tag { id: number, pub_id: Array<number>, name: string | null, color: string | null, total_files: number | null, redundancy_goal: number | null, date_created: string, date_modified: string, tag_files: Array<TagOnFile> | null }
export interface GenerateThumbsForLocationArgs { id: number, path: string }
export interface SetFavoriteArgs { id: number, favorite: boolean }
export interface LibraryConfig { version: string | null, name: string, description: string }
export interface FileInAlbum { date_created: string, album_id: number, album: Album | null, file_id: number, file: File | null }
export interface Statistics { id: number, date_captured: string, total_file_count: number, library_db_size: string, total_bytes_used: string, total_bytes_capacity: string, total_unique_bytes: string, total_bytes_free: string, preview_media_bytes: string }
export interface GetExplorerDirArgs { location_id: number, path: string, limit: number }
export interface JobReport { id: string, name: string, data: Array<number> | null, date_created: string, date_modified: string, status: JobStatus, task_count: number, completed_task_count: number, message: string, seconds_elapsed: number }
export interface Album { id: number, pub_id: Array<number>, name: string, is_hidden: boolean, date_created: string, date_modified: string, files: Array<FileInAlbum> | null }
export interface LabelOnFile { date_created: string, label_id: number, label: Label | null, file_id: number, file: File | null }
export interface SyncEvent { id: number, node_id: number, timestamp: string, record_id: Array<number>, kind: number, column: string | null, value: string, node: Node | null }
export interface Location { id: number, pub_id: Array<number>, node_id: number | null, name: string | null, local_path: string | null, total_capacity: number | null, available_capacity: number | null, filesystem: string | null, disk_type: number | null, is_removable: boolean | null, is_online: boolean, date_created: string, node: Node | null | null, file_paths: Array<FilePath> | null }
export interface Label { id: number, pub_id: Array<number>, name: string | null, date_created: string, date_modified: string, label_files: Array<LabelOnFile> | null }
export interface TagAssignArgs { file_id: number, tag_id: number }
export interface InvalidateOperationEvent { key: string, arg: any }
export interface LibraryArgs<T> { library_id: string, arg: T }
export interface MediaData { id: number, pixel_width: number | null, pixel_height: number | null, longitude: number | null, latitude: number | null, fps: number | null, capture_device_make: string | null, capture_device_model: string | null, capture_device_software: string | null, duration_seconds: number | null, codecs: string | null, streams: number | null, files: File | null | null }
export interface GenerateThumbsForLocationArgs { id: number, path: string }
export interface Volume { name: string, mount_point: string, total_capacity: bigint, available_capacity: bigint, is_removable: boolean, disk_type: string | null, file_system: string | null, is_root_filesystem: boolean }
export interface Key { id: number, checksum: string, name: string | null, date_created: string | null, algorithm: number | null, files: Array<File> | null, file_paths: Array<FilePath> | null }
export interface DirectoryWithContents { directory: FilePath, contents: Array<FilePath> }
export interface FileInSpace { date_created: string, space_id: number, space: Space | null, file_id: number, file: File | null }
export interface ConfigMetadata { version: string | null }
export interface TagOnFile { date_created: string, tag_id: number, tag: Tag | null, file_id: number, file: File | null }
export interface TagUpdateArgs { id: number, name: string | null, color: string | null }
export interface File { id: number, cas_id: string, integrity_checksum: string | null, kind: number, size_in_bytes: string, key_id: number | null, hidden: boolean, favorite: boolean, important: boolean, has_thumbnail: boolean, has_thumbstrip: boolean, has_video_preview: boolean, ipfs_id: string | null, note: string | null, date_created: string, date_modified: string, date_indexed: string, tags: Array<TagOnFile> | null, labels: Array<LabelOnFile> | null, albums: Array<FileInAlbum> | null, spaces: Array<FileInSpace> | null, paths: Array<FilePath> | null, comments: Array<Comment> | null, media_data: MediaData | null | null, key: Key | null | null }
export interface NodeState { version: string | null, id: string, name: string, p2p_port: number | null, data_path: string }
export interface SetNoteArgs { id: number, note: string | null }
export interface LibraryConfig { version: string | null, name: string, description: string }
export interface IdentifyUniqueFilesArgs { id: number, path: string }
export interface Space { id: number, pub_id: Array<number>, name: string | null, description: string | null, date_created: string, date_modified: string, files: Array<FileInSpace> | null }
export interface FilePath { id: number, is_dir: boolean, location_id: number | null, materialized_path: string, name: string, extension: string | null, file_id: number | null, parent_id: number | null, key_id: number | null, date_created: string, date_modified: string, date_indexed: string, file: File | null | null, location: Location | null | null, key: Key | null | null }
export interface Album { id: number, pub_id: Array<number>, name: string, is_hidden: boolean, date_created: string, date_modified: string, files: Array<FileInAlbum> | null }
export interface SetFavoriteArgs { id: number, favorite: boolean }
export interface LocationUpdateArgs { id: number, name: string | null }
export interface Job { id: Array<number>, name: string, node_id: number, action: number, status: number, data: Array<number> | null, task_count: number, completed_task_count: number, date_created: string, date_modified: string, seconds_elapsed: number, nodes: Node | null }
export interface TagAssignArgs { file_id: number, tag_id: number }
export interface Statistics { id: number, date_captured: string, total_file_count: number, library_db_size: string, total_bytes_used: string, total_bytes_capacity: string, total_unique_bytes: string, total_bytes_free: string, preview_media_bytes: string }
export interface FilePath { id: number, is_dir: boolean, location_id: number | null, materialized_path: string, name: string, extension: string | null, file_id: number | null, parent_id: number | null, key_id: number | null, date_created: string, date_modified: string, date_indexed: string, file: File | null | null, location: Location | null | null, key: Key | null | null }
export interface TagCreateArgs { name: string, color: string }
export interface EditLibraryArgs { id: string, name: string | null, description: string | null }
export interface TagUpdateArgs { id: number, name: string | null, color: string | null }
export type JobStatus = "Queued" | "Running" | "Completed" | "Canceled" | "Failed" | "Paused"
export interface MediaData { id: number, pixel_width: number | null, pixel_height: number | null, longitude: number | null, latitude: number | null, fps: number | null, capture_device_make: string | null, capture_device_model: string | null, capture_device_software: string | null, duration_seconds: number | null, codecs: string | null, streams: number | null, files: File | null | null }
export interface NodeConfig { version: string | null, id: string, name: string, p2p_port: number | null }
export interface TagCreateArgs { name: string, color: string }
export interface FileInAlbum { date_created: string, album_id: number, album: Album | null, file_id: number, file: File | null }
export interface Label { id: number, pub_id: Array<number>, name: string | null, date_created: string, date_modified: string, label_files: Array<LabelOnFile> | null }
export interface LabelOnFile { date_created: string, label_id: number, label: Label | null, file_id: number, file: File | null }
export interface EditLibraryArgs { id: string, name: string | null, description: string | null }
export interface Space { id: number, pub_id: Array<number>, name: string | null, description: string | null, date_created: string, date_modified: string, files: Array<FileInSpace> | null }
export interface Comment { id: number, pub_id: Array<number>, content: string, date_created: string, date_modified: string, file_id: number | null, file: File | null | null }
export interface GetExplorerDirArgs { location_id: number, path: string, limit: number }
export type JobStatus = "Queued" | "Running" | "Completed" | "Canceled" | "Failed" | "Paused"
export interface JobReport { id: string, name: string, data: Array<number> | null, date_created: string, date_modified: string, status: JobStatus, task_count: number, completed_task_count: number, message: string, seconds_elapsed: number }
export interface Tag { id: number, pub_id: Array<number>, name: string | null, color: string | null, total_files: number | null, redundancy_goal: number | null, date_created: string, date_modified: string, tag_files: Array<TagOnFile> | null }
export interface LibraryConfigWrapped { uuid: string, config: LibraryConfig }
export interface SyncEvent { id: number, node_id: number, timestamp: string, record_id: Array<number>, kind: number, column: string | null, value: string, node: Node | null }
export interface FileInSpace { date_created: string, space_id: number, space: Space | null, file_id: number, file: File | null }
export interface ConfigMetadata { version: string | null }
export interface InvalidateOperationEvent { key: string, arg: any }
export interface TagOnFile { date_created: string, tag_id: number, tag: Tag | null, file_id: number, file: File | null }
export interface NodeState { version: string | null, id: string, name: string, p2p_port: number | null, data_path: string }
export interface LibraryArgs<T> { library_id: string, arg: T }
export interface Node { id: number, pub_id: Array<number>, name: string, platform: number, version: string | null, last_seen: string, timezone: string | null, date_created: string, sync_events: Array<SyncEvent> | null, jobs: Array<Job> | null, Location: Array<Location> | null }
export interface Key { id: number, checksum: string, name: string | null, date_created: string | null, algorithm: number | null, files: Array<File> | null, file_paths: Array<FilePath> | null }
export interface File { id: number, cas_id: string, integrity_checksum: string | null, kind: number, size_in_bytes: string, key_id: number | null, hidden: boolean, favorite: boolean, important: boolean, has_thumbnail: boolean, has_thumbstrip: boolean, has_video_preview: boolean, ipfs_id: string | null, note: string | null, date_created: string, date_modified: string, date_indexed: string, tags: Array<TagOnFile> | null, labels: Array<LabelOnFile> | null, albums: Array<FileInAlbum> | null, spaces: Array<FileInSpace> | null, paths: Array<FilePath> | null, comments: Array<Comment> | null, media_data: MediaData | null | null, key: Key | null | null }
export interface Volume { name: string, mount_point: string, total_capacity: bigint, available_capacity: bigint, is_removable: boolean, disk_type: string | null, file_system: string | null, is_root_filesystem: boolean }
export interface SetNoteArgs { id: number, note: string | null }

View file

@ -16,7 +16,7 @@ use crate::{
use utils::{InvalidRequests, InvalidateOperationEvent};
pub(crate) type Router = rspc::Router<Ctx>;
pub type Router = rspc::Router<Ctx>;
pub(crate) type RouterBuilder = rspc::RouterBuilder<Ctx>;
/// Represents an internal core event, these are exposed to client via a rspc subscription.
@ -133,5 +133,9 @@ mod tests {
let r = super::mount();
r.export_ts(PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("./index.ts"))
.expect("Error exporting rspc Typescript bindings!");
r.export_ts(
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../apps/mobile/src/types/bindings.ts"),
)
.expect("Error exporting rspc Typescript bindings!");
}
}

View file

@ -1,5 +1,9 @@
use std::sync::{Arc, Mutex};
use std::sync::Arc;
#[cfg(debug_assertions)]
use std::sync::Mutex;
#[cfg(debug_assertions)]
use once_cell::sync::OnceCell;
use rspc::{internal::specta::DataType, Type};
use serde::Serialize;
@ -27,6 +31,7 @@ impl InvalidateOperationEvent {
/// a request to invalidate a specific resource
#[derive(Debug)]
#[allow(dead_code)]
pub(crate) struct InvalidationRequest {
pub key: &'static str,
pub arg_ty: DataType,
@ -35,6 +40,7 @@ pub(crate) struct InvalidationRequest {
/// invalidation request for a specific resource
#[derive(Debug, Default)]
#[allow(dead_code)]
pub(crate) struct InvalidRequests {
pub queries: Vec<InvalidationRequest>,
}

View file

@ -1,3 +1,4 @@
#[cfg(feature = "ffmpeg")]
use ffmpeg_next::format;
#[derive(Default, Debug)]
@ -21,9 +22,10 @@ pub struct Stream {
}
#[derive(Debug)]
#[allow(dead_code)] // TODO: Remove this when we start using ffmpeg
pub enum StreamKind {
// Video(VideoStream),
// Audio(AudioStream),
Video(VideoStream),
Audio(AudioStream),
}
#[derive(Debug)]
@ -31,6 +33,7 @@ pub struct VideoStream {
pub width: u32,
pub height: u32,
pub aspect_ratio: String,
#[cfg(feature = "ffmpeg")]
pub format: format::Pixel,
pub bitrate: usize,
}
@ -38,6 +41,7 @@ pub struct VideoStream {
#[derive(Debug)]
pub struct AudioStream {
pub channels: u16,
#[cfg(feature = "ffmpeg")]
pub format: format::Sample,
pub bitrate: usize,
pub rate: u32,

View file

@ -9,9 +9,7 @@ use tracing_subscriber::{filter::LevelFilter, fmt, prelude::*, EnvFilter};
use tokio::{fs, sync::broadcast};
pub use rspc; // We expose rspc so we can access it in the Desktop app
pub(crate) mod api;
pub mod api;
pub(crate) mod encode;
pub(crate) mod file;
pub(crate) mod job;

View file

@ -1,185 +0,0 @@
use crate::{
file::File,
library::LibraryContext,
prisma::{self, file, tag, tag_on_file},
ClientQuery, CoreError, CoreEvent, CoreResponse, LibraryQuery,
};
use serde::{Deserialize, Serialize};
use thiserror::Error;
use ts_rs::TS;
use uuid::Uuid;
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[ts(export)]
pub struct Tag {
pub id: i32,
pub pub_id: Uuid,
pub name: Option<String>,
pub color: Option<String>,
pub total_files: Option<i32>,
pub redundancy_goal: Option<i32>,
pub date_created: chrono::DateTime<chrono::Utc>,
pub date_modified: chrono::DateTime<chrono::Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[ts(export)]
pub struct TagOnFile {
pub tag_id: i32,
pub tag: Option<Tag>,
pub file_id: i32,
pub file: Option<File>,
pub date_created: chrono::DateTime<chrono::Utc>,
}
impl From<tag::Data> for Tag {
fn from(data: tag::Data) -> Self {
Self {
id: data.id,
pub_id: Uuid::from_slice(&data.pub_id).unwrap(),
name: data.name,
color: data.color,
total_files: data.total_files,
redundancy_goal: data.redundancy_goal,
date_created: data.date_created.into(),
date_modified: data.date_modified.into(),
}
}
}
impl From<tag_on_file::Data> for TagOnFile {
fn from(data: tag_on_file::Data) -> Self {
Self {
tag_id: data.tag_id,
tag: data.tag.map(|t| (*t).into()),
file_id: data.file_id,
file: data.file.map(|f| (*f).into()),
date_created: data.date_created.into(),
}
}
}
#[derive(Serialize, Deserialize, TS, Debug)]
#[ts(export)]
pub struct TagWithFiles {
pub tag: Tag,
pub files_with_tag: Vec<TagOnFile>,
}
#[derive(Error, Debug)]
pub enum TagError {
// #[error("Tag not found")]
// TagNotFound(i32),
#[error("Database error")]
DatabaseError(#[from] prisma::QueryError),
}
pub async fn create_tag(
ctx: LibraryContext,
name: String,
color: String,
) -> Result<CoreResponse, CoreError> {
let created_tag = ctx
.db
.tag()
.create(
tag::pub_id::set(Uuid::new_v4().as_bytes().to_vec()),
vec![tag::name::set(Some(name)), tag::color::set(Some(color))],
)
.exec()
.await
.unwrap();
ctx.emit(CoreEvent::InvalidateQuery(ClientQuery::LibraryQuery {
library_id: ctx.id,
query: LibraryQuery::GetTags,
}))
.await;
Ok(CoreResponse::TagCreateResponse(created_tag.into()))
}
pub async fn update_tag(
ctx: LibraryContext,
id: i32,
name: Option<String>,
color: Option<String>,
) -> Result<CoreResponse, CoreError> {
ctx.db
.tag()
.find_unique(tag::id::equals(id))
.update(vec![tag::name::set(name), tag::color::set(color)])
.exec()
.await
.unwrap();
ctx.emit(CoreEvent::InvalidateQuery(ClientQuery::LibraryQuery {
library_id: ctx.id,
query: LibraryQuery::GetTags,
}))
.await;
Ok(CoreResponse::Success(()))
}
pub async fn tag_assign(
ctx: LibraryContext,
file_id: i32,
tag_id: i32,
) -> Result<CoreResponse, CoreError> {
ctx.db.tag_on_file().create(
tag_on_file::tag::link(tag::UniqueWhereParam::IdEquals(tag_id)),
tag_on_file::file::link(file::UniqueWhereParam::IdEquals(file_id)),
vec![],
);
Ok(CoreResponse::Success(()))
}
pub async fn tag_delete(ctx: LibraryContext, id: i32) -> Result<CoreResponse, CoreError> {
ctx.db
.tag()
.find_unique(tag::id::equals(id))
.delete()
.exec()
.await?
.unwrap();
ctx.emit(CoreEvent::InvalidateQuery(ClientQuery::LibraryQuery {
library_id: ctx.id,
query: LibraryQuery::GetTags,
}))
.await;
Ok(CoreResponse::Success(()))
}
pub async fn get_files_for_tag(ctx: LibraryContext, id: i32) -> Result<CoreResponse, CoreError> {
let tag: Option<Tag> = ctx
.db
.tag()
.find_unique(tag::id::equals(id))
.exec()
.await?
.map(Into::into);
Ok(CoreResponse::GetTag(tag))
}
pub async fn get_all_tags(ctx: LibraryContext) -> Result<CoreResponse, CoreError> {
let tags: Vec<Tag> = ctx
.db
.tag()
.find_many(vec![])
.exec()
.await?
.into_iter()
.map(Into::into)
.collect();
Ok(CoreResponse::GetTags(tags))
}

View file

@ -7,7 +7,7 @@ pre-push:
parallel: true
commands:
type-check:
glob: "*.{ts,tsx}"
glob: '*.{ts,tsx}'
run: pnpm typecheck
lint:
glob: '*.{ts,tsx}'
@ -22,7 +22,5 @@ pre-push:
run: cargo clippy --package spacedrive -- -D warnings
rust-lint-core:
run: cargo clippy --package sdcore --lib -- -D warnings
rust-lint-core-derive:
run: cargo clippy --package core-derive --lib -- -D warnings
rust-lint-server:
run: cargo clippy --package server -- -D warnings

View file

@ -3,7 +3,9 @@
"version": "0.0.0",
"private": true,
"scripts": {
"prep": "pnpm db:gen",
"prep": "pnpm db:gen && pnpm core codegen",
"build": "turbo run build",
"landing-web": "turbo run dev --parallel --filter=@sd/landing --filter=@sd/web",
"db:migrate": "pnpm core prisma migrate dev",
"db:gen": "pnpm core prisma generate",
"format": "prettier --config .prettierrc.cli.js --write \"**/*.{ts,tsx,html,scss,json,yml,md}\"",

View file

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 126 KiB

View file

@ -0,0 +1,15 @@
<svg style="width: 100%; height: auto;" viewBox="0 0 141 110" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 15.5273C0 7.15264 6.78899 0.363647 15.1636 0.363647H35.9094C39.3671 0.363647 42.7035 1.63836 45.2803 3.94395C47.8571 6.24955 51.1935 7.52425 54.6512 7.52425H123.836C132.211 7.52425 139 14.3132 139 22.6879V23.9515C139 32.3262 132.211 39.1152 123.836 39.1152H15.1636C6.78899 39.1152 0 32.3262 0 23.9515V15.5273Z" fill="url(#paint0_linear_0_3)" />
<path d="M0 29.8485C0 23.8001 4.90316 18.897 10.9515 18.897H128.048C134.097 18.897 139 23.8001 139 29.8485V94.7152C139 103.09 132.211 109.879 123.836 109.879H15.1636C6.78899 109.879 0 103.09 0 94.7152V29.8485Z" fill="url(#paint1_linear_0_3)" />
<path d="M0.582787 99.2818L140.005 100" stroke="white" stroke-opacity="0.03" stroke-width="2" />
<defs>
<linearGradient id="paint0_linear_0_3" x1="69.5" y1="0.363647" x2="69.5" y2="39.1152" gradientUnits="userSpaceOnUse">
<stop stop-color="#E7E6E6" />
<stop offset="1" stop-color="white" />
</linearGradient>
<linearGradient id="paint1_linear_0_3" x1="69.5" y1="18.897" x2="69.5" y2="109.879" gradientUnits="userSpaceOnUse">
<stop stop-color="white" />
<stop offset="1" stop-color="#EAEAEA" />
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,16 @@
<svg style="width: 100%; height: auto;" viewBox="0 0 141 110" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 15.5273C0 7.15264 6.78899 0.363647 15.1636 0.363647H35.9094C39.3671 0.363647 42.7035 1.63836 45.2803 3.94395V3.94395C47.8571 6.24955 51.1935 7.52425 54.6512 7.52425H123.836C132.211 7.52425 139 14.3132 139 22.6879V23.9515C139 32.3262 132.211 39.1152 123.836 39.1152H15.1636C6.78899 39.1152 0 32.3262 0 23.9515V15.5273Z" fill="url(#paint0_linear_13_627)" />
<path d="M0 29.8485C0 23.8001 4.90316 18.897 10.9515 18.897H128.048C134.097 18.897 139 23.8001 139 29.8485V94.7152C139 103.09 132.211 109.879 123.836 109.879H15.1636C6.78899 109.879 0 103.09 0 94.7152V29.8485Z" fill="url(#paint1_linear_13_627)" />
<line x1="0.424076" y1="97.8758" x2="139.002" y2="98.1576" stroke="black" stroke-opacity="0.13" stroke-width="1.68485" />
<line x1="0.582788" y1="99.2818" x2="140.005" y2="100" stroke="white" stroke-opacity="0.03" stroke-width="2" />
<defs>
<linearGradient id="paint0_linear_13_627" x1="69.5" y1="0.363647" x2="69.5" y2="39.1152" gradientUnits="userSpaceOnUse">
<stop stop-color="#2D82E7" />
<stop offset="1" stop-color="#083258" />
</linearGradient>
<linearGradient id="paint1_linear_13_627" x1="69.5" y1="18.897" x2="69.5" y2="109.879" gradientUnits="userSpaceOnUse">
<stop stop-color="#319DCB" />
<stop offset="1" stop-color="#264BA8" />
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -18,8 +18,8 @@
},
"dependencies": {
"@rspc/client": "^0.0.5",
"@sd/config": "workspace:*",
"@sd/core": "workspace:*",
"@sd/config": "workspace:*",
"@sd/interface": "workspace:*",
"@tanstack/react-query": "^4.0.10",
"eventemitter3": "^4.0.7",

View file

@ -1,15 +0,0 @@
<svg style="width: 100%; height: auto;" viewBox="0 0 141 110" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 15.5273C0 7.15264 6.78899 0.363647 15.1636 0.363647H35.9094C39.3671 0.363647 42.7035 1.63836 45.2803 3.94395C47.8571 6.24955 51.1935 7.52425 54.6512 7.52425H123.836C132.211 7.52425 139 14.3132 139 22.6879V23.9515C139 32.3262 132.211 39.1152 123.836 39.1152H15.1636C6.78899 39.1152 0 32.3262 0 23.9515V15.5273Z" fill="url(#paint0_linear_0_3)"/>
<path d="M0 29.8485C0 23.8001 4.90316 18.897 10.9515 18.897H128.048C134.097 18.897 139 23.8001 139 29.8485V94.7152C139 103.09 132.211 109.879 123.836 109.879H15.1636C6.78899 109.879 0 103.09 0 94.7152V29.8485Z" fill="url(#paint1_linear_0_3)"/>
<path d="M0.582787 99.2818L140.005 100" stroke="white" stroke-opacity="0.03" stroke-width="2"/>
<defs>
<linearGradient id="paint0_linear_0_3" x1="69.5" y1="0.363647" x2="69.5" y2="39.1152" gradientUnits="userSpaceOnUse">
<stop stop-color="#E7E6E6"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<linearGradient id="paint1_linear_0_3" x1="69.5" y1="18.897" x2="69.5" y2="109.879" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#EAEAEA"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -1,16 +0,0 @@
<svg style="width: 100%; height: auto;" viewBox="0 0 141 110" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 15.5273C0 7.15264 6.78899 0.363647 15.1636 0.363647H35.9094C39.3671 0.363647 42.7035 1.63836 45.2803 3.94395V3.94395C47.8571 6.24955 51.1935 7.52425 54.6512 7.52425H123.836C132.211 7.52425 139 14.3132 139 22.6879V23.9515C139 32.3262 132.211 39.1152 123.836 39.1152H15.1636C6.78899 39.1152 0 32.3262 0 23.9515V15.5273Z" fill="url(#paint0_linear_13_627)"/>
<path d="M0 29.8485C0 23.8001 4.90316 18.897 10.9515 18.897H128.048C134.097 18.897 139 23.8001 139 29.8485V94.7152C139 103.09 132.211 109.879 123.836 109.879H15.1636C6.78899 109.879 0 103.09 0 94.7152V29.8485Z" fill="url(#paint1_linear_13_627)"/>
<line x1="0.424076" y1="97.8758" x2="139.002" y2="98.1576" stroke="black" stroke-opacity="0.13" stroke-width="1.68485"/>
<line x1="0.582788" y1="99.2818" x2="140.005" y2="100" stroke="white" stroke-opacity="0.03" stroke-width="2"/>
<defs>
<linearGradient id="paint0_linear_13_627" x1="69.5" y1="0.363647" x2="69.5" y2="39.1152" gradientUnits="userSpaceOnUse">
<stop stop-color="#2D82E7"/>
<stop offset="1" stop-color="#083258"/>
</linearGradient>
<linearGradient id="paint1_linear_13_627" x1="69.5" y1="18.897" x2="69.5" y2="109.879" gradientUnits="userSpaceOnUse">
<stop stop-color="#319DCB"/>
<stop offset="1" stop-color="#264BA8"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -1,10 +1,10 @@
import { ReactComponent as Folder } from '@sd/assets/svgs/folder.svg';
import { LocationContext } from '@sd/client';
import { FilePath } from '@sd/core';
import clsx from 'clsx';
import React, { useContext } from 'react';
import icons from '../../assets/icons';
import { ReactComponent as Folder } from '../../assets/svg/folder.svg';
import FileThumb from './FileThumb';
interface Props extends React.HTMLAttributes<HTMLDivElement> {

View file

@ -1,8 +1,7 @@
import folderWhiteSvg from '@sd/assets/svgs/folder-white.svg';
import folderSvg from '@sd/assets/svgs/folder.svg';
import React from 'react';
import folderWhiteSvg from '../../assets/svg/folder-white.svg';
import folderSvg from '../../assets/svg/folder.svg';
interface FolderProps {
/**
* Append additional classes to the underlying SVG

View file

@ -83,6 +83,7 @@ importers:
specifiers:
'@heroicons/react': ^1.0.6
'@icons-pack/react-simple-icons': ^5.2.0
'@sd/assets': link:../../packages/assets
'@sd/config': link:../../packages/config
'@sd/interface': link:../../packages/interface
'@sd/ui': link:../../packages/ui
@ -123,6 +124,7 @@ importers:
dependencies:
'@heroicons/react': 1.0.6_react@18.2.0
'@icons-pack/react-simple-icons': 5.2.0_react@18.2.0
'@sd/assets': link:../../packages/assets
'@sd/interface': link:../../packages/interface
'@sd/ui': link:../../packages/ui
'@tryghost/content-api': 1.11.0
@ -2113,8 +2115,8 @@ packages:
'@cspell/dict-docker': 1.1.1
'@cspell/dict-dotnet': 2.0.1
'@cspell/dict-elixir': 2.0.1
'@cspell/dict-en-gb': 1.1.33
'@cspell/dict-en_us': 2.3.0
'@cspell/dict-en-gb': 1.1.33
'@cspell/dict-filetypes': 2.1.1
'@cspell/dict-fonts': 2.0.1
'@cspell/dict-fullstack': 2.0.6
@ -6052,7 +6054,7 @@ packages:
'@babel/plugin-transform-react-jsx-source': 7.18.6_@babel+core@7.18.9
magic-string: 0.26.2
react-refresh: 0.14.0
vite: 3.0.3_sass@1.54.0
vite: 3.0.3
transitivePeerDependencies:
- supports-color
@ -17606,6 +17608,7 @@ packages:
/unified/9.2.0:
resolution: {integrity: sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==}
dependencies:
'@types/unist': 2.0.6
bail: 1.0.5
extend: 3.0.2
is-buffer: 2.0.5
@ -18095,7 +18098,7 @@ packages:
dependencies:
'@rollup/pluginutils': 4.2.1
'@svgr/core': 6.3.1
vite: 3.0.3_sass@1.54.0
vite: 3.0.3
transitivePeerDependencies:
- supports-color
dev: true
@ -18160,7 +18163,6 @@ packages:
rollup: 2.77.1
optionalDependencies:
fsevents: 2.3.2
dev: true
/vite/3.0.3_sass@1.54.0:
resolution: {integrity: sha512-sDIpIcl3mv1NUaSzZwiXGEy1ZoWwwC2vkxUHY6yiDacR6zf//ZFuBJrozO62gedpE43pmxnLATNR5IYUdAEkMQ==}
@ -18188,6 +18190,7 @@ packages:
sass: 1.54.0
optionalDependencies:
fsevents: 2.3.2
dev: true
/vm-browserify/1.1.2:
resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==}