Skip to content

Commit

Permalink
Merge branch 'spacedriveapp:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
Raghav-45 committed Aug 22, 2023
2 parents dfb5192 + e4b0361 commit df4f627
Show file tree
Hide file tree
Showing 363 changed files with 1,853 additions and 483 deletions.
5 changes: 5 additions & 0 deletions apps/mobile/.svgrrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
icon: true,
typescript: true,
svgProps: { fill: 'currentColor' }
};
2 changes: 1 addition & 1 deletion apps/mobile/src/screens/p2p/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useBridgeMutation, useFeatureFlag, useLibraryContext, useP2PEvents } from '@sd/client';
import { useFeatureFlag, useP2PEvents } from '@sd/client';

export function P2P() {
// const pairingResponse = useBridgeMutation('p2p.pairingResponse');
Expand Down
4 changes: 2 additions & 2 deletions apps/mobile/src/types/declarations.d.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
declare module '*.svg' {
import React from 'react';
import { SvgProps } from 'react-native-svg';
const content: React.FC<SvgProps>;
export default content;
// TODO: This is probably not working as intended
export const ReactComponent: React.FC<SVGProps<SVGSVGElement>>;
}

declare module '*.png' {
Expand Down
2 changes: 1 addition & 1 deletion core/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ mod nodes;
pub mod notifications;
mod p2p;
mod preferences;
mod search;
pub(crate) mod search;
mod sync;
mod tags;
pub mod utils;
Expand Down
21 changes: 13 additions & 8 deletions core/src/api/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ struct OptionalRange<T> {
to: Option<T>,
}

#[derive(Deserialize, Type, Debug, Clone, Copy)]
enum SortOrder {
#[derive(Serialize, Deserialize, Type, Debug, Clone, Copy)]
#[serde(rename_all = "PascalCase")]
pub enum SortOrder {
Asc,
Desc,
}
Expand All @@ -50,9 +51,9 @@ impl From<SortOrder> for prisma::SortOrder {
}
}

#[derive(Deserialize, Type, Debug, Clone)]
#[serde(rename_all = "camelCase")]
enum FilePathSearchOrdering {
#[derive(Serialize, Deserialize, Type, Debug, Clone)]
#[serde(rename_all = "camelCase", tag = "field", content = "value")]
pub enum FilePathSearchOrdering {
Name(SortOrder),
SizeInBytes(SortOrder),
DateCreated(SortOrder),
Expand Down Expand Up @@ -183,25 +184,29 @@ impl FilePathFilterArgs {
}
}

#[derive(Deserialize, Type, Debug, Clone)]
#[serde(rename_all = "camelCase")]
enum ObjectSearchOrdering {
#[derive(Serialize, Deserialize, Type, Debug, Clone)]
#[serde(rename_all = "camelCase", tag = "field", content = "value")]
pub enum ObjectSearchOrdering {
DateAccessed(SortOrder),
Kind(SortOrder),
}

impl ObjectSearchOrdering {
fn get_sort_order(&self) -> prisma::SortOrder {
(*match self {
Self::DateAccessed(v) => v,
Self::Kind(v) => v,
})
.into()
}

fn into_param(self) -> object::OrderByWithRelationParam {
let dir = self.get_sort_order();
use object::*;

match self {
Self::DateAccessed(_) => date_accessed::order(dir),
Self::Kind(_) => kind::order(dir),
}
}
}
Expand Down
96 changes: 96 additions & 0 deletions core/src/preferences/library.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
use crate::api::search;
use crate::prisma::PrismaClient;
use serde::{Deserialize, Serialize};
use specta::Type;
use std::collections::BTreeMap;
use std::collections::HashMap;
use uuid::Uuid;

use super::*;

#[derive(Clone, Serialize, Deserialize, Type, Debug)]
#[serde(rename_all = "camelCase")]
pub struct LibraryPreferences {
#[serde(default)]
#[specta(optional)]
location: HashMap<Uuid, Settings<LocationSettings>>,
}

impl LibraryPreferences {
pub async fn write(self, db: &PrismaClient) -> prisma_client_rust::Result<()> {
let kvs = self.to_kvs();

db._batch(kvs.into_upserts(db)).await?;

Ok(())
}

pub async fn read(db: &PrismaClient) -> prisma_client_rust::Result<Self> {
let kvs = db.preference().find_many(vec![]).exec().await?;

let prefs = PreferenceKVs::new(
kvs.into_iter()
.filter_map(|data| {
let a = rmpv::decode::read_value(&mut data.value?.as_slice()).unwrap();

Some((PreferenceKey::new(data.key), PreferenceValue::from_value(a)))
})
.collect(),
);

Ok(prefs.parse())
}
}

#[derive(Clone, Serialize, Deserialize, Type, Debug)]
#[serde(rename_all = "camelCase")]
pub struct LocationSettings {
explorer: ExplorerSettings<search::FilePathSearchOrdering>,
}

#[derive(Clone, Serialize, Deserialize, Type, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ExplorerSettings<TOrder> {
layout_mode: Option<ExplorerLayout>,
grid_item_size: Option<i32>,
media_columns: Option<i32>,
media_aspect_square: Option<bool>,
open_on_double_click: Option<DoubleClickAction>,
show_bytes_in_grid_view: Option<bool>,
col_sizes: Option<BTreeMap<String, i32>>,
// temporary
#[serde(skip_serializing_if = "Option::is_none")]
order: Option<Option<TOrder>>,
}

#[derive(Clone, Serialize, Deserialize, Type, Debug)]
#[serde(rename_all = "camelCase")]
pub enum ExplorerLayout {
Grid,
List,
Media,
}

#[derive(Clone, Serialize, Deserialize, Type, Debug)]
#[serde(rename_all = "camelCase")]
pub enum DoubleClickAction {
OpenFile,
QuickPreview,
}

impl Preferences for LibraryPreferences {
fn to_kvs(self) -> PreferenceKVs {
let Self { location } = self;

location.to_kvs().with_prefix("location")
}

fn from_entries(mut entries: Entries) -> Self {
Self {
location: entries
.remove("location")
.map(|value| HashMap::from_entries(value.expect_nested()))
.unwrap_or_default(),
}
}
}
145 changes: 18 additions & 127 deletions core/src/preferences/mod.rs
Original file line number Diff line number Diff line change
@@ -1,104 +1,32 @@
use crate::prisma::PrismaClient;

use std::collections::HashMap;

use serde::{Deserialize, Serialize};
use specta::Type;
use tracing::error;
use uuid::Uuid;

mod kv;
pub use kv::*;

// Preferences are a set of types that are serialized as a list of key-value pairs,
// where nested type keys are serialized as a dot-separated path.
// They are serailized as a list because this allows preferences to be a synchronisation boundary,
// whereas their values (referred to as settings) will be overwritten.

#[derive(Clone, Serialize, Deserialize, Type, Debug)]
pub struct LibraryPreferences {
#[serde(default)]
#[specta(optional)]
location: HashMap<Uuid, LocationPreferences>,
}
mod library;

impl LibraryPreferences {
pub async fn write(self, db: &PrismaClient) -> prisma_client_rust::Result<()> {
let kvs = self.to_kvs();

db._batch(kvs.into_upserts(db)).await?;

Ok(())
}

pub async fn read(db: &PrismaClient) -> prisma_client_rust::Result<Self> {
let kvs = db.preference().find_many(vec![]).exec().await?;

let prefs = PreferenceKVs::new(
kvs.into_iter()
.filter_map(|data| {
rmpv::decode::read_value(&mut data.value?.as_slice())
.map_err(|e| error!("{e:#?}"))
.ok()
.map(|value| {
(
PreferenceKey::new(data.key),
PreferenceValue::from_value(value),
)
})
})
.collect(),
);

Ok(prefs.parse())
}
}

#[derive(Clone, Serialize, Deserialize, Type, Debug)]
pub struct LocationPreferences {
/// View settings for the location - all writes are overwrites!
#[specta(optional)]
view: Option<LocationViewSettings>,
}

#[derive(Clone, Serialize, Deserialize, Type, Debug)]
pub struct LocationViewSettings {
layout: ExplorerLayout,
list: ListViewSettings,
}
pub use kv::*;
pub use library::*;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use specta::Type;

#[derive(Clone, Serialize, Deserialize, Type, Default, Debug)]
pub struct ListViewSettings {
columns: HashMap<String, ListViewColumnSettings>,
sort_col: Option<String>,
}
use std::collections::HashMap;

#[derive(Clone, Serialize, Deserialize, Type, Default, Debug)]
pub struct ListViewColumnSettings {
hide: bool,
size: Option<i32>,
}
use uuid::Uuid;

#[derive(Clone, Serialize, Deserialize, Type, Debug)]
pub enum ExplorerLayout {
Grid,
List,
Media,
}
#[specta(inline)]
pub struct Settings<V>(V);

impl<V> Preferences for HashMap<Uuid, V>
impl<V> Preferences for HashMap<Uuid, Settings<V>>
where
V: Preferences,
V: Serialize + DeserializeOwned,
{
fn to_kvs(self) -> PreferenceKVs {
PreferenceKVs::new(
self.into_iter()
.flat_map(|(id, value)| {
.map(|(id, value)| {
let mut buf = Uuid::encode_buffer();

let id = id.as_simple().encode_lower(&mut buf);

value.to_kvs().with_prefix(id)
(PreferenceKey::new(id), PreferenceValue::new(value))
})
.collect(),
)
Expand All @@ -107,52 +35,15 @@ where
fn from_entries(entries: Entries) -> Self {
entries
.into_iter()
.map(|(key, value)| {
(
Uuid::parse_str(&key).expect("invalid uuid in preferences"),
V::from_entries(value.expect_nested()),
)
})
.map(|(key, entry)| (Uuid::parse_str(&key).unwrap(), entry.expect_value()))
.collect()
}
}

impl Preferences for LibraryPreferences {
fn to_kvs(self) -> PreferenceKVs {
let Self { location } = self;

location.to_kvs().with_prefix("location")
}

fn from_entries(mut entries: Entries) -> Self {
Self {
location: entries
.remove("location")
.map(|value| HashMap::from_entries(value.expect_nested()))
.unwrap_or_default(),
}
}
}

impl Preferences for LocationPreferences {
fn to_kvs(self) -> PreferenceKVs {
let Self { view } = self;

PreferenceKVs::new(
[view.map(|view| (PreferenceKey::new("view"), PreferenceValue::new(view)))]
.into_iter()
.flatten()
.collect(),
)
}

fn from_entries(mut entries: Entries) -> Self {
Self {
view: entries.remove("view").map(|view| view.expect_value()),
}
}
}

// Preferences are a set of types that are serialized as a list of key-value pairs,
// where nested type keys are serialized as a dot-separated path.
// They are serailized as a list because this allows preferences to be a synchronisation boundary,
// whereas their values (referred to as settings) will be overwritten.
pub trait Preferences {
fn to_kvs(self) -> PreferenceKVs;
fn from_entries(entries: Entries) -> Self;
Expand Down
5 changes: 3 additions & 2 deletions interface/ErrorFallback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { captureException } from '@sentry/browser';
import { FallbackProps } from 'react-error-boundary';
import { useRouteError } from 'react-router';
import { useDebugState } from '@sd/client';
import { Button } from '@sd/ui';
import { Button, Dialogs } from '@sd/ui';
import { showAlertDialog } from './components';
import { useOperatingSystem, useTheme } from './hooks';

Expand Down Expand Up @@ -83,6 +83,7 @@ export function ErrorPage({
(isMacOS ? ' rounded-lg' : '')
}
>
<Dialogs />
<p className="m-3 text-sm font-bold text-ink-faint">APP CRASHED</p>
<h1 className="text-2xl font-bold text-ink">We're past the event horizon...</h1>
<pre className="m-2 max-w-[650px] whitespace-normal text-center text-ink">
Expand Down Expand Up @@ -114,8 +115,8 @@ export function ErrorPage({
</p>
<Button
variant="colored"
className="max-w-xs mt-4 bg-red-500 border-transparent"
onClick={resetHandler}
className="mt-4 max-w-xs border-transparent bg-red-500"
>
Reset & Quit App
</Button>
Expand Down
Loading

0 comments on commit df4f627

Please sign in to comment.