diff --git a/package.json b/package.json index 39897477..22196a3c 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "devDependencies": { "@tailwindcss/typography": "^0.5.9", "@tauri-apps/cli": "^1.2.3", - "@trivago/prettier-plugin-sort-imports": "^4.1.0", + "@trivago/prettier-plugin-sort-imports": "^4.1.1", "@types/node": "^18.14.1", "@types/react": "^18.0.28", "@types/react-dom": "^18.0.11", @@ -55,7 +55,7 @@ "eslint-config-prettier": "^8.6.0", "eslint-plugin-react": "^7.32.2", "eslint-plugin-react-hooks": "^4.6.0", - "husky": "^8.0.0", + "husky": "^8.0.3", "lint-staged": "^13.1.2", "postcss": "^8.4.21", "prettier": "^2.8.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fc513b5c..b13df7b0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,7 +9,7 @@ specifiers: '@tailwindcss/typography': ^0.5.9 '@tauri-apps/api': ^1.2.0 '@tauri-apps/cli': ^1.2.3 - '@trivago/prettier-plugin-sort-imports': ^4.1.0 + '@trivago/prettier-plugin-sort-imports': ^4.1.1 '@types/node': ^18.14.1 '@types/react': ^18.0.28 '@types/react-dom': ^18.0.11 @@ -27,7 +27,7 @@ specifiers: eslint-plugin-react: ^7.32.2 eslint-plugin-react-hooks: ^4.6.0 framer-motion: ^9.1.7 - husky: ^8.0.0 + husky: ^8.0.3 lint-staged: ^13.1.2 moment: ^2.29.4 nanostores: ^0.7.4 @@ -82,7 +82,7 @@ dependencies: devDependencies: '@tailwindcss/typography': 0.5.9_tailwindcss@3.2.7 '@tauri-apps/cli': 1.2.3 - '@trivago/prettier-plugin-sort-imports': 4.1.0_prettier@2.8.4 + '@trivago/prettier-plugin-sort-imports': 4.1.1_prettier@2.8.4 '@types/node': 18.14.1 '@types/react': 18.0.28 '@types/react-dom': 18.0.11 @@ -99,7 +99,7 @@ devDependencies: lint-staged: 13.1.2 postcss: 8.4.21 prettier: 2.8.4 - prettier-plugin-tailwindcss: 0.2.3_3p4xqifn6m4d44r76wgcnqfi3i + prettier-plugin-tailwindcss: 0.2.3_zmkqdpv3ldc45e6wei6qtrbrca prop-types: 15.8.1 tailwindcss: 3.2.7_postcss@8.4.21 typescript: 4.9.5 @@ -1134,8 +1134,8 @@ packages: '@tauri-apps/cli-win32-x64-msvc': 1.2.3 dev: true - /@trivago/prettier-plugin-sort-imports/4.1.0_prettier@2.8.4: - resolution: { integrity: sha512-aTr6QPFaPAAzPRFn9yWB/9yKi3ZAFqfGpxIGLPWuQfYJFGUed+W3KKwxntsoCiNvNE2iuKOg6haMo5KG8WXltg== } + /@trivago/prettier-plugin-sort-imports/4.1.1_prettier@2.8.4: + resolution: { integrity: sha512-dQ2r2uzNr1x6pJsuh/8x0IRA3CBUB+pWEW3J/7N98axqt7SQSm+2fy0FLNXvXGg77xEDC7KHxJlHfLYyi7PDcw== } peerDependencies: '@vue/compiler-sfc': 3.x prettier: 2.x @@ -1609,7 +1609,7 @@ packages: postcss: ^8.1.0 dependencies: browserslist: 4.21.5 - caniuse-lite: 1.0.30001457 + caniuse-lite: 1.0.30001458 fraction.js: 4.2.0 normalize-range: 0.1.2 picocolors: 1.0.0 @@ -1714,8 +1714,8 @@ packages: engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 } hasBin: true dependencies: - caniuse-lite: 1.0.30001457 - electron-to-chromium: 1.4.310 + caniuse-lite: 1.0.30001458 + electron-to-chromium: 1.4.311 node-releases: 2.0.10 update-browserslist-db: 1.0.10_browserslist@4.21.5 @@ -1736,8 +1736,8 @@ packages: engines: { node: '>= 6' } dev: true - /caniuse-lite/1.0.30001457: - resolution: { integrity: sha512-SDIV6bgE1aVbK6XyxdURbUE89zY7+k1BBBaOwYwkNCglXlel/E7mELiHC64HQ+W0xSKlqWhV9Wh7iHxUjMs4fA== } + /caniuse-lite/1.0.30001458: + resolution: { integrity: sha512-lQ1VlUUq5q9ro9X+5gOEyH7i3vm+AYVT1WDCVB69XOZ17KZRhnZ9J0Sqz7wTHQaLBJccNCHq8/Ww5LlOIZbB0w== } /ccount/2.0.1: resolution: { integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg== } @@ -2030,8 +2030,8 @@ packages: resolution: { integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== } dev: true - /electron-to-chromium/1.4.310: - resolution: { integrity: sha512-/xlATgfwkm5uDDwLw5nt/MNEf7c1oazLURMZLy39vOioGYyYzLWIDT8fZMJak6qTiAJ7udFTy7JG7ziyjNutiA== } + /electron-to-chromium/1.4.311: + resolution: { integrity: sha512-RoDlZufvrtr2Nx3Yx5MB8jX3aHIxm8nRWPJm3yVvyHmyKaRvn90RjzB6hNnt0AkhS3IInJdyRfQb4mWhPvUjVw== } /emoji-regex/8.0.0: resolution: { integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== } @@ -2264,7 +2264,7 @@ packages: object.values: 1.1.6 resolve: 1.22.1 semver: 6.3.0 - tsconfig-paths: 3.14.1 + tsconfig-paths: 3.14.2 transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -3923,7 +3923,7 @@ packages: dependencies: '@next/env': 13.2.1 '@swc/helpers': 0.4.14 - caniuse-lite: 1.0.30001457 + caniuse-lite: 1.0.30001458 postcss: 8.4.14 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 @@ -4336,7 +4336,7 @@ packages: engines: { node: '>= 0.8.0' } dev: true - /prettier-plugin-tailwindcss/0.2.3_3p4xqifn6m4d44r76wgcnqfi3i: + /prettier-plugin-tailwindcss/0.2.3_zmkqdpv3ldc45e6wei6qtrbrca: resolution: { integrity: sha512-s2N5Dh7Ao5KTV1mao5ZBnn8EKtUcDPJEkGViZIjI0Ij9TTI5zgTz4IHOxW33jOdjHKa8CSjM88scelUiC5TNRQ== } engines: { node: '>=12.17.0' } peerDependencies: @@ -4388,7 +4388,7 @@ packages: prettier-plugin-twig-melody: optional: true dependencies: - '@trivago/prettier-plugin-sort-imports': 4.1.0_prettier@2.8.4 + '@trivago/prettier-plugin-sort-imports': 4.1.1_prettier@2.8.4 prettier: 2.8.4 dev: true @@ -5146,8 +5146,8 @@ packages: resolution: { integrity: sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g== } dev: false - /tsconfig-paths/3.14.1: - resolution: { integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== } + /tsconfig-paths/3.14.2: + resolution: { integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g== } dependencies: '@types/json5': 0.0.29 json5: 1.0.2 diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index cd1ac1ec..91cbe2c4 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -465,36 +465,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" -[[package]] -name = "curl" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "schannel", - "socket2", - "winapi", -] - -[[package]] -name = "curl-sys" -version = "0.4.59+curl-7.86.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cfce34829f448b08f55b7db6d0009e23e2e86a34e8c2b366269bf5799b4a407" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", - "winapi", -] - [[package]] name = "darling" version = "0.13.4" @@ -1453,18 +1423,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "libz-sys" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "line-wrap" version = "0.1.1" @@ -1519,7 +1477,6 @@ dependencies = [ "tauri", "tauri-build", "tauri-plugin-sql", - "webpage", ] [[package]] @@ -1538,7 +1495,7 @@ dependencies = [ "dirs-next", "objc-foundation", "objc_id", - "time 0.3.17", + "time", ] [[package]] @@ -1564,18 +1521,6 @@ dependencies = [ "tendril", ] -[[package]] -name = "markup5ever_rcdom" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f015da43bcd8d4f144559a3423f4591d69b8ce0652c905374da7205df336ae2b" -dependencies = [ - "html5ever", - "markup5ever", - "tendril", - "xml5ever", -] - [[package]] name = "matchers" version = "0.1.0" @@ -1829,25 +1774,6 @@ dependencies = [ "windows-sys 0.42.0", ] -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7" -dependencies = [ - "autocfg", - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "overload" version = "0.1.1" @@ -2102,7 +2028,7 @@ dependencies = [ "line-wrap", "quick-xml 0.26.0", "serde", - "time 0.3.17", + "time", ] [[package]] @@ -2455,15 +2381,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "schannel" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" -dependencies = [ - "windows-sys 0.42.0", -] - [[package]] name = "scoped-tls" version = "1.0.1" @@ -3083,7 +3000,7 @@ dependencies = [ "sha2", "tauri-utils", "thiserror", - "time 0.3.17", + "time", "uuid 1.3.0", "walkdir", ] @@ -3105,7 +3022,7 @@ dependencies = [ [[package]] name = "tauri-plugin-sql" version = "0.1.0" -source = "git+https://github.com/tauri-apps/plugins-workspace?branch=fix/sql-types#f1a7136b1e0b145ea5c5fb9d336cac0cb1dc6265" +source = "git+https://github.com/tauri-apps/plugins-workspace?branch=dev#8f34eb83e4f9a8c72fd3823a066c94f861f2d021" dependencies = [ "futures", "log", @@ -3256,17 +3173,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", -] - [[package]] name = "time" version = "0.3.17" @@ -3576,12 +3482,6 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -3711,18 +3611,6 @@ dependencies = [ "system-deps 6.0.3", ] -[[package]] -name = "webpage" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d261bbae112cb48a95d3cc9e8873a4e40933bc54ae8eddc1eef70e952dd3b232" -dependencies = [ - "curl", - "html5ever", - "markup5ever_rcdom", - "serde_json", -] - [[package]] name = "webpki" version = "0.22.0" @@ -4087,15 +3975,3 @@ checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" dependencies = [ "libc", ] - -[[package]] -name = "xml5ever" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9234163818fd8e2418fcde330655e757900d4236acd8cc70fef345ef91f6d865" -dependencies = [ - "log", - "mac", - "markup5ever", - "time 0.1.45", -] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 760eeb08..7818d44b 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -17,11 +17,10 @@ tauri-build = { version = "1.2", features = [] } serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } tauri = { version = "1.2", features = ["clipboard-all", "notification-all", "shell-open", "system-tray", "window-start-dragging"] } -webpage = "1.5.0" [dependencies.tauri-plugin-sql] git = "https://github.com/tauri-apps/plugins-workspace" -branch = "fix/sql-types" +branch = "dev" features = ["sqlite"] [target.'cfg(target_os = "macos")'.dependencies] diff --git a/src-tauri/migrations/20230226004139_create_tables.sql b/src-tauri/migrations/20230226004139_create_tables.sql new file mode 100644 index 00000000..22955e5a --- /dev/null +++ b/src-tauri/migrations/20230226004139_create_tables.sql @@ -0,0 +1,40 @@ +-- Add migration script here +-- create accounts +CREATE TABLE + accounts ( + id TEXT PRIMARY KEY, + privkey TEXT NOT NULL, + npub TEXT NOT NULL, + nsec TEXT NOT NULL, + metadata JSON + ); + +-- create follows +CREATE TABLE + follows ( + id INTEGER PRIMARY KEY, + pubkey TEXT NOT NULL, + account TEXT NOT NULL, + metadata JSON + ); + +-- create index for pubkey in follows +CREATE UNIQUE INDEX index_pubkey ON follows (pubkey); + +-- create cache profiles +CREATE TABLE + cache_profiles ( + id TEXT PRIMARY KEY, + metadata JSON, + created_at TEXT, + updated_at TEXT + ); + +-- create cache notes +CREATE TABLE + cache_notes ( + id TEXT PRIMARY KEY, + note JSON, + created_at TEXT, + updated_at TEXT + ); \ No newline at end of file diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 0763c0b3..4b0c9868 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -7,47 +7,12 @@ #[macro_use] extern crate objc; -use std::time::Duration; - -use tauri::{Manager, WindowEvent, SystemTray}; -use webpage::{Webpage, WebpageOptions}; +use tauri::{Manager, SystemTray, WindowEvent}; +use tauri_plugin_sql::{Migration, MigrationKind}; use window_ext::WindowExt; mod window_ext; -#[derive(serde::Serialize)] -struct OpenGraphResponse { - title: String, - description: String, - url: String, - image: String, -} - -async fn fetch_opengraph(url: String) -> OpenGraphResponse { - let options = WebpageOptions { - allow_insecure: false, - max_redirections: 3, - timeout: Duration::from_secs(30), - useragent: "lume - desktop app".to_string(), - ..Default::default() - }; - let result = Webpage::from_url(&url, options).expect("Could not read from URL"); - let html = result.html; - - return OpenGraphResponse { - title: html.opengraph.properties["title"].to_string(), - description: html.opengraph.properties["description"].to_string(), - url: html.opengraph.properties["url"].to_string(), - image: html.opengraph.images[0].url.to_string(), - }; -} - -#[tauri::command] -async fn opengraph(url: String) -> OpenGraphResponse { - let result = fetch_opengraph(url).await; - return result; -} - fn main() { let tray = SystemTray::new(); @@ -60,8 +25,19 @@ fn main() { Ok(()) }) .system_tray(tray) - .invoke_handler(tauri::generate_handler![opengraph]) - .plugin(tauri_plugin_sql::Builder::default().build()) + .plugin( + tauri_plugin_sql::Builder::default() + .add_migrations( + "sqlite:lume.db", + vec![Migration { + version: 1, + description: "create default tables", + sql: include_str!("../migrations/20230226004139_create_tables.sql"), + kind: MigrationKind::Up, + }], + ) + .build(), + ) .on_window_event(|e| { let apply_offset = || { let win = e.window(); diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 49db3ffb..cd066c79 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -19,24 +19,7 @@ export default function Page() { const router = useRouter(); const [loading, setLoading] = useState(true); - const initDB = useCallback(async () => { - if (db) { - await db.execute( - 'CREATE TABLE IF NOT EXISTS accounts (id INTEGER PRIMARY KEY, privkey TEXT NOT NULL, pubkey TEXT NOT NULL, npub TEXT, nsec TEXT, current INTEGER DEFAULT "0" NOT NULL, metadata JSON, UNIQUE(privkey));' - ); - await db.execute('CREATE TABLE IF NOT EXISTS follows (id INTEGER PRIMARY KEY, pubkey TEXT NOT NULL, account TEXT, UNIQUE(pubkey));'); - await db.execute( - 'CREATE TABLE IF NOT EXISTS note_reactions (id INTEGER PRIMARY KEY, reaction_id TEXT NOT NULL, e TEXT, p TEXT, UNIQUE(reaction_id));' - ); - await db.execute('CREATE TABLE IF NOT EXISTS note_replies (id INTEGER PRIMARY KEY, reply_id TEXT NOT NULL, e TEXT, p TEXT, UNIQUE(reply_id));'); - await db.execute('CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, event_id TEXT, event JSON, UNIQUE(event_id));'); - await db.execute('CREATE TABLE IF NOT EXISTS cache_profiles (id INTEGER PRIMARY KEY, pubkey TEXT, metadata JSON, UNIQUE(pubkey));'); - await db.execute('CREATE TABLE IF NOT EXISTS block_pubkeys (id INTEGER PRIMARY KEY, pubkey TEXT, UNIQUE(pubkey));'); - await db.close(); - } - }, []); - - const notification = useCallback(async () => { + const requestNotification = useCallback(async () => { // NOTE: notification don't work in dev mode (only affect MacOS) // ref: https://github.com/tauri-apps/tauri/issues/4965 let permissionGranted = await isPermissionGranted(); @@ -47,18 +30,18 @@ export default function Page() { if (permissionGranted) { sendNotification({ title: 'Lume', body: 'Nostr is awesome' }); } + + return permissionGranted; }, []); const getAccount = useCallback(async () => { - const db = await Database.load('sqlite:lume.db'); - const result = await db.select(`SELECT * FROM accounts WHERE current = "1" ORDER BY id ASC LIMIT 1`); + const result = await db.select(`SELECT id FROM accounts ASC LIMIT 1`); return result; }, []); const getFollows = useCallback(async (account) => { const arr = []; - const db = await Database.load('sqlite:lume.db'); const result: any = await db.select(`SELECT pubkey FROM follows WHERE account = "${account.pubkey}"`); result.forEach((item: { pubkey: string }) => { @@ -69,41 +52,38 @@ export default function Page() { }, []); // Explain: - // Step 1: check DB tables, if not exist then create new table. #TODO: move this function to Rust code - // Step 2: request allow notification from system - // Step 3: get first account. #TODO: get last used account instead (part of multi account feature) - // Step 4: get follows by account + // Step 1: request allow notification from system + // Step 2: get first account. #TODO: get last used account instead (part of multi account feature) + // Step 3: get follows by account useEffect(() => { - initDB() - .then(() => notification()) - .then(() => { - getAccount() - .then((res: any) => { - if (res.length === 0) { - setTimeout(() => { - setLoading(false); - router.push('/onboarding'); - }, 1500); - } else { - // store current user in localstorage - currentUser.set(res[0]); - getFollows(res[0]) - .then(async (res) => { - // store follows in localstorage - follows.set(res); - // redirect to newsfeed - setTimeout(() => { - setLoading(false); - router.push('/feed/following'); - }, 1500); - }) - .catch(console.error); - } - }) - .catch(console.error); - }) - .catch(console.error); - }, [getAccount, getFollows, initDB, notification, router]); + requestNotification().then(() => { + getAccount() + .then((res: any) => { + console.log(res); + if (res.length === 0) { + setTimeout(() => { + setLoading(false); + router.push('/onboarding'); + }, 1500); + } else { + // store current user in localstorage + currentUser.set(res[0]); + getFollows(res[0]) + .then(async (res) => { + // store follows in localstorage + follows.set(res); + // redirect to newsfeed + setTimeout(() => { + setLoading(false); + router.push('/feed/following'); + }, 1500); + }) + .catch(console.error); + } + }) + .catch(console.error); + }); + }, [getAccount, getFollows, requestNotification, router]); return (