diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e64d44a..115e431 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -20,7 +20,7 @@ jobs:
workspaces: ". -> target"
- name: Run server tests
- run: cargo test -p notto-server
+ run: cargo test -p nooto-server
test-rust-client:
name: Rust Client Tests
@@ -50,7 +50,7 @@ jobs:
workspaces: ". -> target"
- name: Run client tests
- run: cargo test -p notto
+ run: cargo test -p nooto
test-frontend:
name: Frontend Tests
@@ -62,12 +62,12 @@ jobs:
with:
node-version: 22
cache: npm
- cache-dependency-path: notto-client/package-lock.json
+ cache-dependency-path: client/package-lock.json
- name: Install dependencies
- working-directory: notto-client
+ working-directory: client
run: npm ci
- name: Run Vitest
- working-directory: notto-client
+ working-directory: client
run: npm test
diff --git a/AGENTS.md b/AGENTS.md
index a2e187a..5305db4 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -13,7 +13,7 @@ git checkout -b claude-dev # Create and switch to claude-dev branch
## Project Overview
-Notto is an end-to-end encrypted note-taking application built with:
+Nooto is an end-to-end encrypted note-taking application built with:
- **Client**: Tauri v2 desktop app (Rust backend + React frontend with TypeScript)
- **Server**: Axum HTTP server for sync
- **Database**: MariaDB (server), SQLite (client)
@@ -23,7 +23,7 @@ Notto is an end-to-end encrypted note-taking application built with:
### Frontend (Tauri Client)
```bash
-cd notto-client
+cd nooto-client
npm install # Install dependencies
npm run tauri dev # Run development mode
npm run build # Build TypeScript
@@ -32,7 +32,7 @@ npm run tauri build # Build production app
### Backend (Sync Server)
```bash
-cd notto-server
+cd server
cargo run # Run development server (listens on 0.0.0.0:3000)
cargo build --release # Build production binary
```
@@ -44,7 +44,7 @@ docker-compose up # Start MariaDB and Adminer (port 8080)
docker-compose down # Stop services
```
-Database connection string must be set in `notto-server/.env` as `DATABASE_URL`.
+Database connection string must be set in `server/.env` as `DATABASE_URL`.
### Workspace Commands
From project root:
@@ -58,8 +58,8 @@ cargo test # Run tests for all crates
### Workspace Structure
This is a Cargo workspace with three members:
- `shared/`: Common types and structs shared between client and server
-- `notto-client/src-tauri/`: Tauri backend (Rust)
-- `notto-server/`: HTTP sync server (Axum)
+- `client/src-tauri/`: Tauri backend (Rust)
+- `server/`: HTTP sync server (Axum)
### Client Architecture (Tauri)
diff --git a/Cargo.toml b/Cargo.toml
index 7736430..ceb04d2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,3 +1,3 @@
[workspace]
resolver = "3"
-members = ["shared", "notto-client/src-tauri", "notto-server"]
\ No newline at end of file
+members = ["shared", "client/src-tauri", "server"]
\ No newline at end of file
diff --git a/README.md b/README.md
index 59c743f..aaf6131 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Notto
+# Nooto
See [Technical infos](./technical_infos.md) file for more informations on what I'm building.
diff --git a/notto-client/index.html b/client/index.html
similarity index 75%
rename from notto-client/index.html
rename to client/index.html
index 844dcc2..8c5cab9 100644
--- a/notto-client/index.html
+++ b/client/index.html
@@ -2,9 +2,9 @@
-
+
- Notto
+ Nooto
diff --git a/notto-client/package-lock.json b/client/package-lock.json
similarity index 99%
rename from notto-client/package-lock.json
rename to client/package-lock.json
index 88c2b4f..0706921 100644
--- a/notto-client/package-lock.json
+++ b/client/package-lock.json
@@ -1,11 +1,11 @@
{
- "name": "notto",
+ "name": "nooto",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
- "name": "notto",
+ "name": "nooto",
"version": "0.1.0",
"dependencies": {
"@dnd-kit/core": "^6.3.1",
diff --git a/notto-client/package.json b/client/package.json
similarity index 98%
rename from notto-client/package.json
rename to client/package.json
index 5410ebc..b660f99 100644
--- a/notto-client/package.json
+++ b/client/package.json
@@ -1,5 +1,5 @@
{
- "name": "notto",
+ "name": "nooto",
"private": true,
"version": "0.1.0",
"type": "module",
diff --git a/notto-client/public/notto.svg b/client/public/notto.svg
similarity index 100%
rename from notto-client/public/notto.svg
rename to client/public/notto.svg
diff --git a/notto-client/public/tauri.svg b/client/public/tauri.svg
similarity index 100%
rename from notto-client/public/tauri.svg
rename to client/public/tauri.svg
diff --git a/notto-client/public/vite.svg b/client/public/vite.svg
similarity index 100%
rename from notto-client/public/vite.svg
rename to client/public/vite.svg
diff --git a/notto-client/src-tauri/.gitignore b/client/src-tauri/.gitignore
similarity index 100%
rename from notto-client/src-tauri/.gitignore
rename to client/src-tauri/.gitignore
diff --git a/notto-client/src-tauri/Cargo.toml b/client/src-tauri/Cargo.toml
similarity index 98%
rename from notto-client/src-tauri/Cargo.toml
rename to client/src-tauri/Cargo.toml
index b96bef6..dd01819 100644
--- a/notto-client/src-tauri/Cargo.toml
+++ b/client/src-tauri/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "notto"
+name = "nooto"
version = "0.0.15"
description = "A Tauri App"
authors = ["Clément Pera"]
diff --git a/notto-client/src-tauri/build.rs b/client/src-tauri/build.rs
similarity index 100%
rename from notto-client/src-tauri/build.rs
rename to client/src-tauri/build.rs
diff --git a/notto-client/src-tauri/capabilities/default.json b/client/src-tauri/capabilities/default.json
similarity index 100%
rename from notto-client/src-tauri/capabilities/default.json
rename to client/src-tauri/capabilities/default.json
diff --git a/notto-client/src-tauri/gen/android/.editorconfig b/client/src-tauri/gen/android/.editorconfig
similarity index 100%
rename from notto-client/src-tauri/gen/android/.editorconfig
rename to client/src-tauri/gen/android/.editorconfig
diff --git a/notto-client/src-tauri/gen/android/.gitignore b/client/src-tauri/gen/android/.gitignore
similarity index 100%
rename from notto-client/src-tauri/gen/android/.gitignore
rename to client/src-tauri/gen/android/.gitignore
diff --git a/notto-client/src-tauri/gen/android/app/.gitignore b/client/src-tauri/gen/android/app/.gitignore
similarity index 75%
rename from notto-client/src-tauri/gen/android/app/.gitignore
rename to client/src-tauri/gen/android/app/.gitignore
index d581a63..9555952 100644
--- a/notto-client/src-tauri/gen/android/app/.gitignore
+++ b/client/src-tauri/gen/android/app/.gitignore
@@ -1,4 +1,4 @@
-/src/main/java/com/notto/app/generated
+/src/main/java/com/nooto/app/generated
/src/main/jniLibs/**/*.so
/src/main/assets/tauri.conf.json
/tauri.build.gradle.kts
diff --git a/notto-client/src-tauri/gen/android/app/build.gradle.kts b/client/src-tauri/gen/android/app/build.gradle.kts
similarity index 96%
rename from notto-client/src-tauri/gen/android/app/build.gradle.kts
rename to client/src-tauri/gen/android/app/build.gradle.kts
index fafdbe6..3373f0c 100644
--- a/notto-client/src-tauri/gen/android/app/build.gradle.kts
+++ b/client/src-tauri/gen/android/app/build.gradle.kts
@@ -15,10 +15,10 @@ val tauriProperties = Properties().apply {
android {
compileSdk = 36
- namespace = "com.notto.app"
+ namespace = "com.nooto.app"
defaultConfig {
manifestPlaceholders["usesCleartextTraffic"] = "false"
- applicationId = "com.notto.app"
+ applicationId = "com.nooto.app"
minSdk = 24
targetSdk = 36
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
diff --git a/notto-client/src-tauri/gen/android/app/proguard-rules.pro b/client/src-tauri/gen/android/app/proguard-rules.pro
similarity index 100%
rename from notto-client/src-tauri/gen/android/app/proguard-rules.pro
rename to client/src-tauri/gen/android/app/proguard-rules.pro
diff --git a/notto-client/src-tauri/gen/android/app/src/main/AndroidManifest.xml b/client/src-tauri/gen/android/app/src/main/AndroidManifest.xml
similarity index 97%
rename from notto-client/src-tauri/gen/android/app/src/main/AndroidManifest.xml
rename to client/src-tauri/gen/android/app/src/main/AndroidManifest.xml
index 37296ea..fa71e1a 100644
--- a/notto-client/src-tauri/gen/android/app/src/main/AndroidManifest.xml
+++ b/client/src-tauri/gen/android/app/src/main/AndroidManifest.xml
@@ -8,7 +8,7 @@
+ // we're not using WebView::getUrl() here because it needs to be executed on the main thread
+ // and it would slow down the Ipc
+ // so instead we track the current URL on the webview client
+ this.ipc(webViewClient.currentUrl, m)
+ }
+ }
+
+ companion object {
+ init {
+ System.loadLibrary("notto_lib")
+ }
+ }
+
+ private external fun ipc(url: String, message: String)
+
+
+}
diff --git a/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/Logger.kt b/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/Logger.kt
new file mode 100644
index 0000000..8fd08e8
--- /dev/null
+++ b/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/Logger.kt
@@ -0,0 +1,89 @@
+/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */
+
+// Copyright 2020-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: MIT
+
+@file:Suppress("unused", "MemberVisibilityCanBePrivate")
+
+package com.notto.app
+
+// taken from https://github.com/ionic-team/capacitor/blob/6658bca41e78239347e458175b14ca8bd5c1d6e8/android/capacitor/src/main/java/com/getcapacitor/Logger.java
+
+import android.text.TextUtils
+import android.util.Log
+
+class Logger {
+ companion object {
+ private const val LOG_TAG_CORE = "Tauri"
+
+ fun tags(vararg subtags: String): String {
+ return if (subtags.isNotEmpty()) {
+ LOG_TAG_CORE + "/" + TextUtils.join("/", subtags)
+ } else LOG_TAG_CORE
+ }
+
+ fun verbose(message: String) {
+ verbose(LOG_TAG_CORE, message)
+ }
+
+ private fun verbose(tag: String, message: String) {
+ if (!shouldLog()) {
+ return
+ }
+ Log.v(tag, message)
+ }
+
+ fun debug(message: String) {
+ debug(LOG_TAG_CORE, message)
+ }
+
+ fun debug(tag: String, message: String) {
+ if (!shouldLog()) {
+ return
+ }
+ Log.d(tag, message)
+ }
+
+ fun info(message: String) {
+ info(LOG_TAG_CORE, message)
+ }
+
+ fun info(tag: String, message: String) {
+ if (!shouldLog()) {
+ return
+ }
+ Log.i(tag, message)
+ }
+
+ fun warn(message: String) {
+ warn(LOG_TAG_CORE, message)
+ }
+
+ fun warn(tag: String, message: String) {
+ if (!shouldLog()) {
+ return
+ }
+ Log.w(tag, message)
+ }
+
+ fun error(message: String) {
+ error(LOG_TAG_CORE, message, null)
+ }
+
+ fun error(message: String, e: Throwable?) {
+ error(LOG_TAG_CORE, message, e)
+ }
+
+ fun error(tag: String, message: String, e: Throwable?) {
+ if (!shouldLog()) {
+ return
+ }
+ Log.e(tag, message, e)
+ }
+
+ private fun shouldLog(): Boolean {
+ return BuildConfig.DEBUG
+ }
+ }
+}
diff --git a/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/PermissionHelper.kt b/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/PermissionHelper.kt
new file mode 100644
index 0000000..840473e
--- /dev/null
+++ b/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/PermissionHelper.kt
@@ -0,0 +1,117 @@
+/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */
+
+// Copyright 2020-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: MIT
+
+package com.notto.app
+
+// taken from https://github.com/ionic-team/capacitor/blob/6658bca41e78239347e458175b14ca8bd5c1d6e8/android/capacitor/src/main/java/com/getcapacitor/PermissionHelper.java
+
+import android.content.Context
+import android.content.pm.PackageManager
+import android.os.Build
+import androidx.core.app.ActivityCompat
+import java.util.ArrayList
+
+object PermissionHelper {
+ /**
+ * Checks if a list of given permissions are all granted by the user
+ *
+ * @param permissions Permissions to check.
+ * @return True if all permissions are granted, false if at least one is not.
+ */
+ fun hasPermissions(context: Context?, permissions: Array): Boolean {
+ for (perm in permissions) {
+ if (ActivityCompat.checkSelfPermission(
+ context!!,
+ perm
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
+ return false
+ }
+ }
+ return true
+ }
+
+ /**
+ * Check whether the given permission has been defined in the AndroidManifest.xml
+ *
+ * @param permission A permission to check.
+ * @return True if the permission has been defined in the Manifest, false if not.
+ */
+ fun hasDefinedPermission(context: Context, permission: String): Boolean {
+ var hasPermission = false
+ val requestedPermissions = getManifestPermissions(context)
+ if (!requestedPermissions.isNullOrEmpty()) {
+ val requestedPermissionsList = listOf(*requestedPermissions)
+ val requestedPermissionsArrayList = ArrayList(requestedPermissionsList)
+ if (requestedPermissionsArrayList.contains(permission)) {
+ hasPermission = true
+ }
+ }
+ return hasPermission
+ }
+
+ /**
+ * Check whether all of the given permissions have been defined in the AndroidManifest.xml
+ * @param context the app context
+ * @param permissions a list of permissions
+ * @return true only if all permissions are defined in the AndroidManifest.xml
+ */
+ fun hasDefinedPermissions(context: Context, permissions: Array): Boolean {
+ for (permission in permissions) {
+ if (!hasDefinedPermission(context, permission)) {
+ return false
+ }
+ }
+ return true
+ }
+
+ /**
+ * Get the permissions defined in AndroidManifest.xml
+ *
+ * @return The permissions defined in AndroidManifest.xml
+ */
+ private fun getManifestPermissions(context: Context): Array? {
+ var requestedPermissions: Array? = null
+ try {
+ val pm = context.packageManager
+ val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ pm.getPackageInfo(context.packageName, PackageManager.PackageInfoFlags.of(PackageManager.GET_PERMISSIONS.toLong()))
+ } else {
+ @Suppress("DEPRECATION")
+ pm.getPackageInfo(context.packageName, PackageManager.GET_PERMISSIONS)
+ }
+ if (packageInfo != null) {
+ requestedPermissions = packageInfo.requestedPermissions
+ }
+ } catch (_: Exception) {
+ }
+ return requestedPermissions
+ }
+
+ /**
+ * Given a list of permissions, return a new list with the ones not present in AndroidManifest.xml
+ *
+ * @param neededPermissions The permissions needed.
+ * @return The permissions not present in AndroidManifest.xml
+ */
+ fun getUndefinedPermissions(context: Context, neededPermissions: Array): Array {
+ val undefinedPermissions = ArrayList()
+ val requestedPermissions = getManifestPermissions(context)
+ if (!requestedPermissions.isNullOrEmpty()) {
+ val requestedPermissionsList = listOf(*requestedPermissions)
+ val requestedPermissionsArrayList = ArrayList(requestedPermissionsList)
+ for (permission in neededPermissions) {
+ if (!requestedPermissionsArrayList.contains(permission)) {
+ undefinedPermissions.add(permission)
+ }
+ }
+ var undefinedPermissionArray = arrayOfNulls(undefinedPermissions.size)
+ undefinedPermissionArray = undefinedPermissions.toArray(undefinedPermissionArray)
+ return undefinedPermissionArray
+ }
+ return neededPermissions
+ }
+}
diff --git a/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/RustWebChromeClient.kt b/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/RustWebChromeClient.kt
new file mode 100644
index 0000000..6f92614
--- /dev/null
+++ b/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/RustWebChromeClient.kt
@@ -0,0 +1,495 @@
+/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */
+
+// Copyright 2020-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: MIT
+
+@file:Suppress("ObsoleteSdkInt", "RedundantOverride", "QueryPermissionsNeeded", "SimpleDateFormat")
+
+package com.notto.app
+
+// taken from https://github.com/ionic-team/capacitor/blob/6658bca41e78239347e458175b14ca8bd5c1d6e8/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java
+
+import android.Manifest
+import android.app.Activity
+import android.app.AlertDialog
+import android.content.ActivityNotFoundException
+import android.content.DialogInterface
+import android.content.Intent
+import android.net.Uri
+import android.os.Build
+import android.os.Environment
+import android.provider.MediaStore
+import android.view.View
+import android.webkit.*
+import android.widget.EditText
+import androidx.activity.result.ActivityResult
+import androidx.activity.result.ActivityResultCallback
+import androidx.activity.result.ActivityResultLauncher
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.core.content.FileProvider
+import java.io.File
+import java.io.IOException
+import java.text.SimpleDateFormat
+import java.util.*
+
+class RustWebChromeClient(appActivity: WryActivity) : WebChromeClient() {
+ private interface PermissionListener {
+ fun onPermissionSelect(isGranted: Boolean?)
+ }
+
+ private interface ActivityResultListener {
+ fun onActivityResult(result: ActivityResult?)
+ }
+
+ private val activity: WryActivity
+ private var permissionLauncher: ActivityResultLauncher>
+ private var activityLauncher: ActivityResultLauncher
+ private var permissionListener: PermissionListener? = null
+ private var activityListener: ActivityResultListener? = null
+
+ init {
+ activity = appActivity
+ val permissionCallback =
+ ActivityResultCallback { isGranted: Map ->
+ if (permissionListener != null) {
+ var granted = true
+ for ((_, value) in isGranted) {
+ if (!value) granted = false
+ }
+ permissionListener!!.onPermissionSelect(granted)
+ }
+ }
+ permissionLauncher =
+ activity.registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions(), permissionCallback)
+ activityLauncher = activity.registerForActivityResult(
+ ActivityResultContracts.StartActivityForResult()
+ ) { result ->
+ if (activityListener != null) {
+ activityListener!!.onActivityResult(result)
+ }
+ }
+ }
+
+ /**
+ * Render web content in `view`.
+ *
+ * Both this method and [.onHideCustomView] are required for
+ * rendering web content in full screen.
+ *
+ * @see [](https://developer.android.com/reference/android/webkit/WebChromeClient.onShowCustomView
+ ) */
+ override fun onShowCustomView(view: View, callback: CustomViewCallback) {
+ callback.onCustomViewHidden()
+ super.onShowCustomView(view, callback)
+ }
+
+ /**
+ * Render web content in the original Web View again.
+ *
+ * Do not remove this method--@see #onShowCustomView(View, CustomViewCallback).
+ */
+ override fun onHideCustomView() {
+ super.onHideCustomView()
+ }
+
+ override fun onPermissionRequest(request: PermissionRequest) {
+ val isRequestPermissionRequired = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
+ val permissionList: MutableList = ArrayList()
+ if (listOf(*request.resources).contains("android.webkit.resource.VIDEO_CAPTURE")) {
+ permissionList.add(Manifest.permission.CAMERA)
+ }
+ if (listOf(*request.resources).contains("android.webkit.resource.AUDIO_CAPTURE")) {
+ permissionList.add(Manifest.permission.MODIFY_AUDIO_SETTINGS)
+ permissionList.add(Manifest.permission.RECORD_AUDIO)
+ }
+ if (permissionList.isNotEmpty() && isRequestPermissionRequired) {
+ val permissions = permissionList.toTypedArray()
+ permissionListener = object : PermissionListener {
+ override fun onPermissionSelect(isGranted: Boolean?) {
+ if (isGranted == true) {
+ request.grant(request.resources)
+ } else {
+ request.deny()
+ }
+ }
+ }
+ permissionLauncher.launch(permissions)
+ } else {
+ request.grant(request.resources)
+ }
+ }
+
+ /**
+ * Show the browser alert modal
+ * @param view
+ * @param url
+ * @param message
+ * @param result
+ * @return
+ */
+ override fun onJsAlert(view: WebView, url: String, message: String, result: JsResult): Boolean {
+ if (activity.isFinishing) {
+ return true
+ }
+ val builder = AlertDialog.Builder(view.context)
+ builder
+ .setMessage(message)
+ .setPositiveButton(
+ "OK"
+ ) { dialog: DialogInterface, _: Int ->
+ dialog.dismiss()
+ result.confirm()
+ }
+ .setOnCancelListener { dialog: DialogInterface ->
+ dialog.dismiss()
+ result.cancel()
+ }
+ val dialog = builder.create()
+ dialog.show()
+ return true
+ }
+
+ /**
+ * Show the browser confirm modal
+ * @param view
+ * @param url
+ * @param message
+ * @param result
+ * @return
+ */
+ override fun onJsConfirm(view: WebView, url: String, message: String, result: JsResult): Boolean {
+ if (activity.isFinishing) {
+ return true
+ }
+ val builder = AlertDialog.Builder(view.context)
+ builder
+ .setMessage(message)
+ .setPositiveButton(
+ "OK"
+ ) { dialog: DialogInterface, _: Int ->
+ dialog.dismiss()
+ result.confirm()
+ }
+ .setNegativeButton(
+ "Cancel"
+ ) { dialog: DialogInterface, _: Int ->
+ dialog.dismiss()
+ result.cancel()
+ }
+ .setOnCancelListener { dialog: DialogInterface ->
+ dialog.dismiss()
+ result.cancel()
+ }
+ val dialog = builder.create()
+ dialog.show()
+ return true
+ }
+
+ /**
+ * Show the browser prompt modal
+ * @param view
+ * @param url
+ * @param message
+ * @param defaultValue
+ * @param result
+ * @return
+ */
+ override fun onJsPrompt(
+ view: WebView,
+ url: String,
+ message: String,
+ defaultValue: String,
+ result: JsPromptResult
+ ): Boolean {
+ if (activity.isFinishing) {
+ return true
+ }
+ val builder = AlertDialog.Builder(view.context)
+ val input = EditText(view.context)
+ builder
+ .setMessage(message)
+ .setView(input)
+ .setPositiveButton(
+ "OK"
+ ) { dialog: DialogInterface, _: Int ->
+ dialog.dismiss()
+ val inputText1 = input.text.toString().trim { it <= ' ' }
+ result.confirm(inputText1)
+ }
+ .setNegativeButton(
+ "Cancel"
+ ) { dialog: DialogInterface, _: Int ->
+ dialog.dismiss()
+ result.cancel()
+ }
+ .setOnCancelListener { dialog: DialogInterface ->
+ dialog.dismiss()
+ result.cancel()
+ }
+ val dialog = builder.create()
+ dialog.show()
+ return true
+ }
+
+ /**
+ * Handle the browser geolocation permission prompt
+ * @param origin
+ * @param callback
+ */
+ override fun onGeolocationPermissionsShowPrompt(
+ origin: String,
+ callback: GeolocationPermissions.Callback
+ ) {
+ super.onGeolocationPermissionsShowPrompt(origin, callback)
+ Logger.debug("onGeolocationPermissionsShowPrompt: DOING IT HERE FOR ORIGIN: $origin")
+ val geoPermissions =
+ arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION)
+ if (!PermissionHelper.hasPermissions(activity, geoPermissions)) {
+ permissionListener = object : PermissionListener {
+ override fun onPermissionSelect(isGranted: Boolean?) {
+ if (isGranted == true) {
+ callback.invoke(origin, true, false)
+ } else {
+ val coarsePermission =
+ arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
+ PermissionHelper.hasPermissions(activity, coarsePermission)
+ ) {
+ callback.invoke(origin, true, false)
+ } else {
+ callback.invoke(origin, false, false)
+ }
+ }
+ }
+ }
+ permissionLauncher.launch(geoPermissions)
+ } else {
+ // permission is already granted
+ callback.invoke(origin, true, false)
+ Logger.debug("onGeolocationPermissionsShowPrompt: has required permission")
+ }
+ }
+
+ override fun onShowFileChooser(
+ webView: WebView,
+ filePathCallback: ValueCallback?>,
+ fileChooserParams: FileChooserParams
+ ): Boolean {
+ val acceptTypes = listOf(*fileChooserParams.acceptTypes)
+ val captureEnabled = fileChooserParams.isCaptureEnabled
+ val capturePhoto = captureEnabled && acceptTypes.contains("image/*")
+ val captureVideo = captureEnabled && acceptTypes.contains("video/*")
+ if (capturePhoto || captureVideo) {
+ if (isMediaCaptureSupported) {
+ showMediaCaptureOrFilePicker(filePathCallback, fileChooserParams, captureVideo)
+ } else {
+ permissionListener = object : PermissionListener {
+ override fun onPermissionSelect(isGranted: Boolean?) {
+ if (isGranted == true) {
+ showMediaCaptureOrFilePicker(filePathCallback, fileChooserParams, captureVideo)
+ } else {
+ Logger.warn(Logger.tags("FileChooser"), "Camera permission not granted")
+ filePathCallback.onReceiveValue(null)
+ }
+ }
+ }
+ val camPermission = arrayOf(Manifest.permission.CAMERA)
+ permissionLauncher.launch(camPermission)
+ }
+ } else {
+ showFilePicker(filePathCallback, fileChooserParams)
+ }
+ return true
+ }
+
+ private val isMediaCaptureSupported: Boolean
+ get() {
+ val permissions = arrayOf(Manifest.permission.CAMERA)
+ return PermissionHelper.hasPermissions(activity, permissions) ||
+ !PermissionHelper.hasDefinedPermission(activity, Manifest.permission.CAMERA)
+ }
+
+ private fun showMediaCaptureOrFilePicker(
+ filePathCallback: ValueCallback?>,
+ fileChooserParams: FileChooserParams,
+ isVideo: Boolean
+ ) {
+ val isVideoCaptureSupported = true
+ val shown = if (isVideo && isVideoCaptureSupported) {
+ showVideoCapturePicker(filePathCallback)
+ } else {
+ showImageCapturePicker(filePathCallback)
+ }
+ if (!shown) {
+ Logger.warn(
+ Logger.tags("FileChooser"),
+ "Media capture intent could not be launched. Falling back to default file picker."
+ )
+ showFilePicker(filePathCallback, fileChooserParams)
+ }
+ }
+
+ private fun showImageCapturePicker(filePathCallback: ValueCallback?>): Boolean {
+ val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
+ if (takePictureIntent.resolveActivity(activity.packageManager) == null) {
+ return false
+ }
+ val imageFileUri: Uri = try {
+ createImageFileUri()
+ } catch (ex: Exception) {
+ Logger.error("Unable to create temporary media capture file: " + ex.message)
+ return false
+ }
+ takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageFileUri)
+ activityListener = object : ActivityResultListener {
+ override fun onActivityResult(result: ActivityResult?) {
+ var res: Array? = null
+ if (result?.resultCode == Activity.RESULT_OK) {
+ res = arrayOf(imageFileUri)
+ }
+ filePathCallback.onReceiveValue(res)
+ }
+ }
+ activityLauncher.launch(takePictureIntent)
+ return true
+ }
+
+ private fun showVideoCapturePicker(filePathCallback: ValueCallback?>): Boolean {
+ val takeVideoIntent = Intent(MediaStore.ACTION_VIDEO_CAPTURE)
+ if (takeVideoIntent.resolveActivity(activity.packageManager) == null) {
+ return false
+ }
+ activityListener = object : ActivityResultListener {
+ override fun onActivityResult(result: ActivityResult?) {
+ var res: Array? = null
+ if (result?.resultCode == Activity.RESULT_OK) {
+ res = arrayOf(result.data!!.data)
+ }
+ filePathCallback.onReceiveValue(res)
+ }
+ }
+ activityLauncher.launch(takeVideoIntent)
+ return true
+ }
+
+ private fun showFilePicker(
+ filePathCallback: ValueCallback?>,
+ fileChooserParams: FileChooserParams
+ ) {
+ val intent = fileChooserParams.createIntent()
+ if (fileChooserParams.mode == FileChooserParams.MODE_OPEN_MULTIPLE) {
+ intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
+ }
+ if (fileChooserParams.acceptTypes.size > 1 || intent.type!!.startsWith(".")) {
+ val validTypes = getValidTypes(fileChooserParams.acceptTypes)
+ intent.putExtra(Intent.EXTRA_MIME_TYPES, validTypes)
+ if (intent.type!!.startsWith(".")) {
+ intent.type = validTypes[0]
+ }
+ }
+ try {
+ activityListener = object : ActivityResultListener {
+ override fun onActivityResult(result: ActivityResult?) {
+ val res: Array?
+ val resultIntent = result?.data
+ if (result?.resultCode == Activity.RESULT_OK && resultIntent!!.clipData != null) {
+ val numFiles = resultIntent.clipData!!.itemCount
+ res = arrayOfNulls(numFiles)
+ for (i in 0 until numFiles) {
+ res[i] = resultIntent.clipData!!.getItemAt(i).uri
+ }
+ } else {
+ res = FileChooserParams.parseResult(
+ result?.resultCode ?: 0,
+ resultIntent
+ )
+ }
+ filePathCallback.onReceiveValue(res)
+ }
+ }
+ activityLauncher.launch(intent)
+ } catch (e: ActivityNotFoundException) {
+ filePathCallback.onReceiveValue(null)
+ }
+ }
+
+ private fun getValidTypes(currentTypes: Array): Array {
+ val validTypes: MutableList = ArrayList()
+ val mtm = MimeTypeMap.getSingleton()
+ for (mime in currentTypes) {
+ if (mime.startsWith(".")) {
+ val extension = mime.substring(1)
+ val extensionMime = mtm.getMimeTypeFromExtension(extension)
+ if (extensionMime != null && !validTypes.contains(extensionMime)) {
+ validTypes.add(extensionMime)
+ }
+ } else if (!validTypes.contains(mime)) {
+ validTypes.add(mime)
+ }
+ }
+ val validObj: Array = validTypes.toTypedArray()
+ return Arrays.copyOf(
+ validObj, validObj.size,
+ Array::class.java
+ )
+ }
+
+ override fun onConsoleMessage(consoleMessage: ConsoleMessage): Boolean {
+ val tag: String = Logger.tags("Console")
+ if (consoleMessage.message() != null && isValidMsg(consoleMessage.message())) {
+ val msg = String.format(
+ "File: %s - Line %d - Msg: %s",
+ consoleMessage.sourceId(),
+ consoleMessage.lineNumber(),
+ consoleMessage.message()
+ )
+ val level = consoleMessage.messageLevel().name
+ if ("ERROR".equals(level, ignoreCase = true)) {
+ Logger.error(tag, msg, null)
+ } else if ("WARNING".equals(level, ignoreCase = true)) {
+ Logger.warn(tag, msg)
+ } else if ("TIP".equals(level, ignoreCase = true)) {
+ Logger.debug(tag, msg)
+ } else {
+ Logger.info(tag, msg)
+ }
+ }
+ return true
+ }
+
+ private fun isValidMsg(msg: String): Boolean {
+ return !(msg.contains("%cresult %c") ||
+ msg.contains("%cnative %c") ||
+ msg.equals("[object Object]", ignoreCase = true) ||
+ msg.equals("console.groupEnd", ignoreCase = true))
+ }
+
+ @Throws(IOException::class)
+ private fun createImageFileUri(): Uri {
+ val photoFile = createImageFile(activity)
+ return FileProvider.getUriForFile(
+ activity,
+ activity.packageName.toString() + ".fileprovider",
+ photoFile
+ )
+ }
+
+ @Throws(IOException::class)
+ private fun createImageFile(activity: Activity): File {
+ // Create an image file name
+ val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
+ val imageFileName = "JPEG_" + timeStamp + "_"
+ val storageDir = activity.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
+ return File.createTempFile(imageFileName, ".jpg", storageDir)
+ }
+
+ override fun onReceivedTitle(
+ view: WebView,
+ title: String
+ ) {
+ handleReceivedTitle(view, title)
+ }
+
+ private external fun handleReceivedTitle(webview: WebView, title: String)
+}
diff --git a/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/RustWebView.kt b/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/RustWebView.kt
new file mode 100644
index 0000000..b4e8d12
--- /dev/null
+++ b/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/RustWebView.kt
@@ -0,0 +1,101 @@
+/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */
+
+// Copyright 2020-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: MIT
+
+@file:Suppress("unused", "SetJavaScriptEnabled")
+
+package com.notto.app
+
+import android.annotation.SuppressLint
+import android.webkit.*
+import android.content.Context
+import androidx.webkit.WebViewCompat
+import androidx.webkit.WebViewFeature
+import kotlin.collections.Map
+
+@SuppressLint("RestrictedApi")
+class RustWebView(context: Context, val initScripts: Array, val id: String): WebView(context) {
+ val isDocumentStartScriptEnabled: Boolean
+
+ init {
+ settings.javaScriptEnabled = true
+ settings.domStorageEnabled = true
+ settings.setGeolocationEnabled(true)
+ settings.databaseEnabled = true
+ settings.mediaPlaybackRequiresUserGesture = false
+ settings.javaScriptCanOpenWindowsAutomatically = true
+
+ if (WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) {
+ isDocumentStartScriptEnabled = true
+ for (script in initScripts) {
+ WebViewCompat.addDocumentStartJavaScript(this, script, setOf("*"));
+ }
+ } else {
+ isDocumentStartScriptEnabled = false
+ }
+
+
+ }
+
+ fun loadUrlMainThread(url: String) {
+ post {
+ loadUrl(url)
+ }
+ }
+
+ fun loadUrlMainThread(url: String, additionalHttpHeaders: Map) {
+ post {
+ loadUrl(url, additionalHttpHeaders)
+ }
+ }
+
+ override fun loadUrl(url: String) {
+ if (!shouldOverride(url)) {
+ super.loadUrl(url);
+ }
+ }
+
+ override fun loadUrl(url: String, additionalHttpHeaders: Map) {
+ if (!shouldOverride(url)) {
+ super.loadUrl(url, additionalHttpHeaders);
+ }
+ }
+
+ fun loadHTMLMainThread(html: String) {
+ post {
+ super.loadData(html, "text/html", null)
+ }
+ }
+
+ fun evalScript(id: Int, script: String) {
+ post {
+ super.evaluateJavascript(script) { result ->
+ onEval(id, result)
+ }
+ }
+ }
+
+ fun clearAllBrowsingData() {
+ try {
+ super.getContext().deleteDatabase("webviewCache.db")
+ super.getContext().deleteDatabase("webview.db")
+ super.clearCache(true)
+ super.clearHistory()
+ super.clearFormData()
+ } catch (ex: Exception) {
+ Logger.error("Unable to create temporary media capture file: " + ex.message)
+ }
+ }
+
+ fun getCookies(url: String): String {
+ val cookieManager = CookieManager.getInstance()
+ return cookieManager.getCookie(url)
+ }
+
+ private external fun shouldOverride(url: String): Boolean
+ private external fun onEval(id: Int, result: String)
+
+
+}
diff --git a/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/RustWebViewClient.kt b/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/RustWebViewClient.kt
new file mode 100644
index 0000000..cb8276b
--- /dev/null
+++ b/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/RustWebViewClient.kt
@@ -0,0 +1,107 @@
+/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */
+
+// Copyright 2020-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: MIT
+
+package com.notto.app
+
+import android.net.Uri
+import android.webkit.*
+import android.content.Context
+import android.graphics.Bitmap
+import android.os.Handler
+import android.os.Looper
+import androidx.webkit.WebViewAssetLoader
+
+class RustWebViewClient(context: Context): WebViewClient() {
+ private val interceptedState = mutableMapOf()
+ var currentUrl: String = "about:blank"
+ private var lastInterceptedUrl: Uri? = null
+ private var pendingUrlRedirect: String? = null
+
+ private val assetLoader = WebViewAssetLoader.Builder()
+ .setDomain(assetLoaderDomain())
+ .addPathHandler("/", WebViewAssetLoader.AssetsPathHandler(context))
+ .build()
+
+ override fun shouldInterceptRequest(
+ view: WebView,
+ request: WebResourceRequest
+ ): WebResourceResponse? {
+ pendingUrlRedirect?.let {
+ Handler(Looper.getMainLooper()).post {
+ view.loadUrl(it)
+ }
+ pendingUrlRedirect = null
+ return null
+ }
+
+ lastInterceptedUrl = request.url
+ return if (withAssetLoader()) {
+ assetLoader.shouldInterceptRequest(request.url)
+ } else {
+ val rustWebview = view as RustWebView;
+ val response = handleRequest(rustWebview.id, request, rustWebview.isDocumentStartScriptEnabled)
+ interceptedState[request.url.toString()] = response != null
+ return response
+ }
+ }
+
+ override fun shouldOverrideUrlLoading(
+ view: WebView,
+ request: WebResourceRequest
+ ): Boolean {
+ return shouldOverride(request.url.toString())
+ }
+
+ override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) {
+ currentUrl = url
+ if (interceptedState[url] == false) {
+ val webView = view as RustWebView
+ for (script in webView.initScripts) {
+ view.evaluateJavascript(script, null)
+ }
+ }
+ return onPageLoading(url)
+ }
+
+ override fun onPageFinished(view: WebView, url: String) {
+ onPageLoaded(url)
+ }
+
+ override fun onReceivedError(
+ view: WebView,
+ request: WebResourceRequest,
+ error: WebResourceError
+ ) {
+ // we get a net::ERR_CONNECTION_REFUSED when an external URL redirects to a custom protocol
+ // e.g. oauth flow, because shouldInterceptRequest is not called on redirects
+ // so we must force retry here with loadUrl() to get a chance of the custom protocol to kick in
+ if (error.errorCode == ERROR_CONNECT && request.isForMainFrame && request.url != lastInterceptedUrl) {
+ // prevent the default error page from showing
+ view.stopLoading()
+ // without this initial loadUrl the app is stuck
+ view.loadUrl(request.url.toString())
+ // ensure the URL is actually loaded - for some reason there's a race condition and we need to call loadUrl() again later
+ pendingUrlRedirect = request.url.toString()
+ } else {
+ super.onReceivedError(view, request, error)
+ }
+ }
+
+ companion object {
+ init {
+ System.loadLibrary("notto_lib")
+ }
+ }
+
+ private external fun assetLoaderDomain(): String
+ private external fun withAssetLoader(): Boolean
+ private external fun handleRequest(webviewId: String, request: WebResourceRequest, isDocumentStartScriptEnabled: Boolean): WebResourceResponse?
+ private external fun shouldOverride(url: String): Boolean
+ private external fun onPageLoading(url: String)
+ private external fun onPageLoaded(url: String)
+
+
+}
diff --git a/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/TauriActivity.kt b/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/TauriActivity.kt
new file mode 100644
index 0000000..2c00791
--- /dev/null
+++ b/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/TauriActivity.kt
@@ -0,0 +1,51 @@
+// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: MIT
+
+/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */
+
+package com.notto.app
+
+import android.content.Intent
+import android.content.res.Configuration
+import app.tauri.plugin.PluginManager
+
+abstract class TauriActivity : WryActivity() {
+ var pluginManager: PluginManager = PluginManager(this)
+ override val handleBackNavigation: Boolean = false
+
+ override fun onNewIntent(intent: Intent) {
+ super.onNewIntent(intent)
+ pluginManager.onNewIntent(intent)
+ }
+
+ override fun onResume() {
+ super.onResume()
+ pluginManager.onResume()
+ }
+
+ override fun onPause() {
+ super.onPause()
+ pluginManager.onPause()
+ }
+
+ override fun onRestart() {
+ super.onRestart()
+ pluginManager.onRestart()
+ }
+
+ override fun onStop() {
+ super.onStop()
+ pluginManager.onStop()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ pluginManager.onDestroy()
+ }
+
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ super.onConfigurationChanged(newConfig)
+ pluginManager.onConfigurationChanged(newConfig)
+ }
+}
diff --git a/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/WryActivity.kt b/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/WryActivity.kt
new file mode 100644
index 0000000..cbd8a3e
--- /dev/null
+++ b/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/WryActivity.kt
@@ -0,0 +1,137 @@
+/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */
+
+// Copyright 2020-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: MIT
+
+package com.notto.app
+
+import com.notto.app.RustWebView
+import android.annotation.SuppressLint
+import android.os.Build
+import android.os.Bundle
+import android.webkit.WebView
+import android.view.KeyEvent
+import androidx.appcompat.app.AppCompatActivity
+
+abstract class WryActivity : AppCompatActivity() {
+ private lateinit var mWebView: RustWebView
+ open val handleBackNavigation: Boolean = true
+
+ open fun onWebViewCreate(webView: WebView) { }
+
+ fun setWebView(webView: RustWebView) {
+ mWebView = webView
+ onWebViewCreate(webView)
+ }
+
+ val version: String
+ @SuppressLint("WebViewApiAvailability", "ObsoleteSdkInt")
+ get() {
+ // Check getCurrentWebViewPackage() directly if above Android 8
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ return WebView.getCurrentWebViewPackage()?.versionName ?: ""
+ }
+
+ // Otherwise manually check WebView versions
+ var webViewPackage = "com.google.android.webview"
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ webViewPackage = "com.android.chrome"
+ }
+ try {
+ @Suppress("DEPRECATION")
+ val info = packageManager.getPackageInfo(webViewPackage, 0)
+ return info.versionName.toString()
+ } catch (ex: Exception) {
+ Logger.warn("Unable to get package info for '$webViewPackage'$ex")
+ }
+
+ try {
+ @Suppress("DEPRECATION")
+ val info = packageManager.getPackageInfo("com.android.webview", 0)
+ return info.versionName.toString()
+ } catch (ex: Exception) {
+ Logger.warn("Unable to get package info for 'com.android.webview'$ex")
+ }
+
+ // Could not detect any webview, return empty string
+ return ""
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ create(this)
+ }
+
+ override fun onStart() {
+ super.onStart()
+ start()
+ }
+
+ override fun onResume() {
+ super.onResume()
+ resume()
+ }
+
+ override fun onPause() {
+ super.onPause()
+ pause()
+ }
+
+ override fun onStop() {
+ super.onStop()
+ stop()
+ }
+
+ override fun onWindowFocusChanged(hasFocus: Boolean) {
+ super.onWindowFocusChanged(hasFocus)
+ focus(hasFocus)
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ save()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ destroy()
+ onActivityDestroy()
+ }
+
+ override fun onLowMemory() {
+ super.onLowMemory()
+ memory()
+ }
+
+ override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
+ if (handleBackNavigation && keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) {
+ mWebView.goBack()
+ return true
+ }
+ return super.onKeyDown(keyCode, event)
+ }
+
+ fun getAppClass(name: String): Class<*> {
+ return Class.forName(name)
+ }
+
+ companion object {
+ init {
+ System.loadLibrary("notto_lib")
+ }
+ }
+
+ private external fun create(activity: WryActivity)
+ private external fun start()
+ private external fun resume()
+ private external fun pause()
+ private external fun stop()
+ private external fun save()
+ private external fun destroy()
+ private external fun onActivityDestroy()
+ private external fun memory()
+ private external fun focus(focus: Boolean)
+
+
+}
diff --git a/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/proguard-wry.pro b/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/proguard-wry.pro
new file mode 100644
index 0000000..33b2b40
--- /dev/null
+++ b/client/src-tauri/gen/android/app/src/main/java/com/notto/app/generated/proguard-wry.pro
@@ -0,0 +1,35 @@
+# THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!!
+
+# Copyright 2020-2023 Tauri Programme within The Commons Conservancy
+# SPDX-License-Identifier: Apache-2.0
+# SPDX-License-Identifier: MIT
+
+-keep class com.notto.app.* {
+ native ;
+}
+
+-keep class com.notto.app.WryActivity {
+ public (...);
+
+ void setWebView(com.notto.app.RustWebView);
+ java.lang.Class getAppClass(...);
+ java.lang.String getVersion();
+}
+
+-keep class com.notto.app.Ipc {
+ public (...);
+
+ @android.webkit.JavascriptInterface public ;
+}
+
+-keep class com.notto.app.RustWebView {
+ public (...);
+
+ void loadUrlMainThread(...);
+ void loadHTMLMainThread(...);
+ void evalScript(...);
+}
+
+-keep class com.notto.app.RustWebChromeClient,com.notto.app.RustWebViewClient {
+ public (...);
+}
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/client/src-tauri/gen/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
similarity index 100%
rename from notto-client/src-tauri/gen/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
rename to client/src-tauri/gen/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/drawable/ic_launcher_background.xml b/client/src-tauri/gen/android/app/src/main/res/drawable/ic_launcher_background.xml
similarity index 100%
rename from notto-client/src-tauri/gen/android/app/src/main/res/drawable/ic_launcher_background.xml
rename to client/src-tauri/gen/android/app/src/main/res/drawable/ic_launcher_background.xml
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/layout/activity_main.xml b/client/src-tauri/gen/android/app/src/main/res/layout/activity_main.xml
similarity index 100%
rename from notto-client/src-tauri/gen/android/app/src/main/res/layout/activity_main.xml
rename to client/src-tauri/gen/android/app/src/main/res/layout/activity_main.xml
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/client/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
similarity index 100%
rename from notto-client/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
rename to client/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/client/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
similarity index 100%
rename from notto-client/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
rename to client/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/client/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
similarity index 100%
rename from notto-client/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
rename to client/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/client/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
similarity index 100%
rename from notto-client/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
rename to client/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/client/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
similarity index 100%
rename from notto-client/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
rename to client/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/client/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
similarity index 100%
rename from notto-client/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
rename to client/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/client/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
similarity index 100%
rename from notto-client/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
rename to client/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/client/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
similarity index 100%
rename from notto-client/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
rename to client/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/client/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
similarity index 100%
rename from notto-client/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
rename to client/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/client/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
similarity index 100%
rename from notto-client/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
rename to client/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/client/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
similarity index 100%
rename from notto-client/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
rename to client/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/client/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
similarity index 100%
rename from notto-client/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
rename to client/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/client/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
similarity index 100%
rename from notto-client/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
rename to client/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/client/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
similarity index 100%
rename from notto-client/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
rename to client/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/client/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
similarity index 100%
rename from notto-client/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
rename to client/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/values-night/themes.xml b/client/src-tauri/gen/android/app/src/main/res/values-night/themes.xml
similarity index 74%
rename from notto-client/src-tauri/gen/android/app/src/main/res/values-night/themes.xml
rename to client/src-tauri/gen/android/app/src/main/res/values-night/themes.xml
index 938501c..0b42a12 100644
--- a/notto-client/src-tauri/gen/android/app/src/main/res/values-night/themes.xml
+++ b/client/src-tauri/gen/android/app/src/main/res/values-night/themes.xml
@@ -1,6 +1,6 @@
-
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/values/colors.xml b/client/src-tauri/gen/android/app/src/main/res/values/colors.xml
similarity index 100%
rename from notto-client/src-tauri/gen/android/app/src/main/res/values/colors.xml
rename to client/src-tauri/gen/android/app/src/main/res/values/colors.xml
diff --git a/client/src-tauri/gen/android/app/src/main/res/values/strings.xml b/client/src-tauri/gen/android/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..52f6c33
--- /dev/null
+++ b/client/src-tauri/gen/android/app/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+ nooto
+ nooto
+
\ No newline at end of file
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/values/themes.xml b/client/src-tauri/gen/android/app/src/main/res/values/themes.xml
similarity index 74%
rename from notto-client/src-tauri/gen/android/app/src/main/res/values/themes.xml
rename to client/src-tauri/gen/android/app/src/main/res/values/themes.xml
index 938501c..0b42a12 100644
--- a/notto-client/src-tauri/gen/android/app/src/main/res/values/themes.xml
+++ b/client/src-tauri/gen/android/app/src/main/res/values/themes.xml
@@ -1,6 +1,6 @@
-
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/xml/file_paths.xml b/client/src-tauri/gen/android/app/src/main/res/xml/file_paths.xml
similarity index 100%
rename from notto-client/src-tauri/gen/android/app/src/main/res/xml/file_paths.xml
rename to client/src-tauri/gen/android/app/src/main/res/xml/file_paths.xml
diff --git a/notto-client/src-tauri/gen/android/build.gradle.kts b/client/src-tauri/gen/android/build.gradle.kts
similarity index 100%
rename from notto-client/src-tauri/gen/android/build.gradle.kts
rename to client/src-tauri/gen/android/build.gradle.kts
diff --git a/notto-client/src-tauri/gen/android/buildSrc/build.gradle.kts b/client/src-tauri/gen/android/buildSrc/build.gradle.kts
similarity index 100%
rename from notto-client/src-tauri/gen/android/buildSrc/build.gradle.kts
rename to client/src-tauri/gen/android/buildSrc/build.gradle.kts
diff --git a/notto-client/src-tauri/gen/android/buildSrc/src/main/java/com/notto/app/kotlin/BuildTask.kt b/client/src-tauri/gen/android/buildSrc/src/main/java/com/notto/app/kotlin/BuildTask.kt
similarity index 100%
rename from notto-client/src-tauri/gen/android/buildSrc/src/main/java/com/notto/app/kotlin/BuildTask.kt
rename to client/src-tauri/gen/android/buildSrc/src/main/java/com/notto/app/kotlin/BuildTask.kt
diff --git a/notto-client/src-tauri/gen/android/buildSrc/src/main/java/com/notto/app/kotlin/RustPlugin.kt b/client/src-tauri/gen/android/buildSrc/src/main/java/com/notto/app/kotlin/RustPlugin.kt
similarity index 100%
rename from notto-client/src-tauri/gen/android/buildSrc/src/main/java/com/notto/app/kotlin/RustPlugin.kt
rename to client/src-tauri/gen/android/buildSrc/src/main/java/com/notto/app/kotlin/RustPlugin.kt
diff --git a/notto-client/src-tauri/gen/android/gradle.properties b/client/src-tauri/gen/android/gradle.properties
similarity index 100%
rename from notto-client/src-tauri/gen/android/gradle.properties
rename to client/src-tauri/gen/android/gradle.properties
diff --git a/notto-client/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.jar b/client/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
rename from notto-client/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.jar
rename to client/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.jar
diff --git a/notto-client/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties b/client/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties
similarity index 100%
rename from notto-client/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties
rename to client/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties
diff --git a/notto-client/src-tauri/gen/android/gradlew b/client/src-tauri/gen/android/gradlew
similarity index 100%
rename from notto-client/src-tauri/gen/android/gradlew
rename to client/src-tauri/gen/android/gradlew
diff --git a/notto-client/src-tauri/gen/android/gradlew.bat b/client/src-tauri/gen/android/gradlew.bat
similarity index 100%
rename from notto-client/src-tauri/gen/android/gradlew.bat
rename to client/src-tauri/gen/android/gradlew.bat
diff --git a/notto-client/src-tauri/gen/android/settings.gradle b/client/src-tauri/gen/android/settings.gradle
similarity index 100%
rename from notto-client/src-tauri/gen/android/settings.gradle
rename to client/src-tauri/gen/android/settings.gradle
diff --git a/notto-client/src-tauri/icons/128x128.png b/client/src-tauri/icons/128x128.png
similarity index 100%
rename from notto-client/src-tauri/icons/128x128.png
rename to client/src-tauri/icons/128x128.png
diff --git a/notto-client/src-tauri/icons/128x128@2x.png b/client/src-tauri/icons/128x128@2x.png
similarity index 100%
rename from notto-client/src-tauri/icons/128x128@2x.png
rename to client/src-tauri/icons/128x128@2x.png
diff --git a/notto-client/src-tauri/icons/32x32.png b/client/src-tauri/icons/32x32.png
similarity index 100%
rename from notto-client/src-tauri/icons/32x32.png
rename to client/src-tauri/icons/32x32.png
diff --git a/notto-client/src-tauri/icons/Square107x107Logo.png b/client/src-tauri/icons/Square107x107Logo.png
similarity index 100%
rename from notto-client/src-tauri/icons/Square107x107Logo.png
rename to client/src-tauri/icons/Square107x107Logo.png
diff --git a/notto-client/src-tauri/icons/Square142x142Logo.png b/client/src-tauri/icons/Square142x142Logo.png
similarity index 100%
rename from notto-client/src-tauri/icons/Square142x142Logo.png
rename to client/src-tauri/icons/Square142x142Logo.png
diff --git a/notto-client/src-tauri/icons/Square150x150Logo.png b/client/src-tauri/icons/Square150x150Logo.png
similarity index 100%
rename from notto-client/src-tauri/icons/Square150x150Logo.png
rename to client/src-tauri/icons/Square150x150Logo.png
diff --git a/notto-client/src-tauri/icons/Square284x284Logo.png b/client/src-tauri/icons/Square284x284Logo.png
similarity index 100%
rename from notto-client/src-tauri/icons/Square284x284Logo.png
rename to client/src-tauri/icons/Square284x284Logo.png
diff --git a/notto-client/src-tauri/icons/Square30x30Logo.png b/client/src-tauri/icons/Square30x30Logo.png
similarity index 100%
rename from notto-client/src-tauri/icons/Square30x30Logo.png
rename to client/src-tauri/icons/Square30x30Logo.png
diff --git a/notto-client/src-tauri/icons/Square310x310Logo.png b/client/src-tauri/icons/Square310x310Logo.png
similarity index 100%
rename from notto-client/src-tauri/icons/Square310x310Logo.png
rename to client/src-tauri/icons/Square310x310Logo.png
diff --git a/notto-client/src-tauri/icons/Square44x44Logo.png b/client/src-tauri/icons/Square44x44Logo.png
similarity index 100%
rename from notto-client/src-tauri/icons/Square44x44Logo.png
rename to client/src-tauri/icons/Square44x44Logo.png
diff --git a/notto-client/src-tauri/icons/Square71x71Logo.png b/client/src-tauri/icons/Square71x71Logo.png
similarity index 100%
rename from notto-client/src-tauri/icons/Square71x71Logo.png
rename to client/src-tauri/icons/Square71x71Logo.png
diff --git a/notto-client/src-tauri/icons/Square89x89Logo.png b/client/src-tauri/icons/Square89x89Logo.png
similarity index 100%
rename from notto-client/src-tauri/icons/Square89x89Logo.png
rename to client/src-tauri/icons/Square89x89Logo.png
diff --git a/notto-client/src-tauri/icons/StoreLogo.png b/client/src-tauri/icons/StoreLogo.png
similarity index 100%
rename from notto-client/src-tauri/icons/StoreLogo.png
rename to client/src-tauri/icons/StoreLogo.png
diff --git a/notto-client/src-tauri/icons/icon.icns b/client/src-tauri/icons/icon.icns
similarity index 100%
rename from notto-client/src-tauri/icons/icon.icns
rename to client/src-tauri/icons/icon.icns
diff --git a/notto-client/src-tauri/icons/icon.ico b/client/src-tauri/icons/icon.ico
similarity index 100%
rename from notto-client/src-tauri/icons/icon.ico
rename to client/src-tauri/icons/icon.ico
diff --git a/notto-client/src-tauri/icons/icon.png b/client/src-tauri/icons/icon.png
similarity index 100%
rename from notto-client/src-tauri/icons/icon.png
rename to client/src-tauri/icons/icon.png
diff --git a/notto-client/src-tauri/src/commands.rs b/client/src-tauri/src/commands.rs
similarity index 100%
rename from notto-client/src-tauri/src/commands.rs
rename to client/src-tauri/src/commands.rs
diff --git a/notto-client/src-tauri/src/crypt/mod.rs b/client/src-tauri/src/crypt/mod.rs
similarity index 99%
rename from notto-client/src-tauri/src/crypt/mod.rs
rename to client/src-tauri/src/crypt/mod.rs
index 594e696..5207730 100644
--- a/notto-client/src-tauri/src/crypt/mod.rs
+++ b/client/src-tauri/src/crypt/mod.rs
@@ -260,7 +260,7 @@ mod tests {
#[test]
fn encrypt_decrypt_roundtrip() {
let key = random_key();
- let plaintext = b"hello, notto!";
+ let plaintext = b"hello, nooto!";
let (ciphertext, nonce) = encrypt_data(plaintext, &key).unwrap();
let decrypted = decrypt_data(&ciphertext, &nonce, &key).unwrap();
diff --git a/notto-client/src-tauri/src/db/mod.rs b/client/src-tauri/src/db/mod.rs
similarity index 100%
rename from notto-client/src-tauri/src/db/mod.rs
rename to client/src-tauri/src/db/mod.rs
diff --git a/notto-client/src-tauri/src/db/operations.rs b/client/src-tauri/src/db/operations.rs
similarity index 100%
rename from notto-client/src-tauri/src/db/operations.rs
rename to client/src-tauri/src/db/operations.rs
diff --git a/notto-client/src-tauri/src/db/schema.rs b/client/src-tauri/src/db/schema.rs
similarity index 100%
rename from notto-client/src-tauri/src/db/schema.rs
rename to client/src-tauri/src/db/schema.rs
diff --git a/notto-client/src-tauri/src/lib.rs b/client/src-tauri/src/lib.rs
similarity index 98%
rename from notto-client/src-tauri/src/lib.rs
rename to client/src-tauri/src/lib.rs
index 7f783a9..7e3314d 100644
--- a/notto-client/src-tauri/src/lib.rs
+++ b/client/src-tauri/src/lib.rs
@@ -41,7 +41,7 @@ pub fn run() {
.path()
.app_data_dir()
.map_err(|e| anyhow::anyhow!("Failed to get app data directory: {e}"))?
- .join("notto.db");
+ .join("nooto.db");
let database = db::init(db_path)
.map_err(|e| anyhow::anyhow!("Failed to initialise database: {e:#}"))?;
diff --git a/notto-client/src-tauri/src/main.rs b/client/src-tauri/src/main.rs
similarity index 100%
rename from notto-client/src-tauri/src/main.rs
rename to client/src-tauri/src/main.rs
diff --git a/notto-client/src-tauri/src/sync/mod.rs b/client/src-tauri/src/sync/mod.rs
similarity index 100%
rename from notto-client/src-tauri/src/sync/mod.rs
rename to client/src-tauri/src/sync/mod.rs
diff --git a/notto-client/src-tauri/src/sync/operations.rs b/client/src-tauri/src/sync/operations.rs
similarity index 100%
rename from notto-client/src-tauri/src/sync/operations.rs
rename to client/src-tauri/src/sync/operations.rs
diff --git a/notto-client/src-tauri/src/sync/service.rs b/client/src-tauri/src/sync/service.rs
similarity index 100%
rename from notto-client/src-tauri/src/sync/service.rs
rename to client/src-tauri/src/sync/service.rs
diff --git a/notto-client/src-tauri/tauri.conf.json b/client/src-tauri/tauri.conf.json
similarity index 87%
rename from notto-client/src-tauri/tauri.conf.json
rename to client/src-tauri/tauri.conf.json
index 6348554..b8de73a 100644
--- a/notto-client/src-tauri/tauri.conf.json
+++ b/client/src-tauri/tauri.conf.json
@@ -1,8 +1,8 @@
{
"$schema": "https://schema.tauri.app/config/2",
- "productName": "notto",
+ "productName": "nooto",
"version": "0.1.0",
- "identifier": "com.notto.app",
+ "identifier": "com.nooto.app",
"build": {
"beforeDevCommand": "npm run dev",
"devUrl": "http://localhost:1420",
@@ -12,7 +12,7 @@
"app": {
"windows": [
{
- "title": "notto",
+ "title": "nooto",
"width": 800,
"height": 600
}
diff --git a/notto-client/src/App.css b/client/src/App.css
similarity index 100%
rename from notto-client/src/App.css
rename to client/src/App.css
diff --git a/notto-client/src/App.tsx b/client/src/App.tsx
similarity index 100%
rename from notto-client/src/App.tsx
rename to client/src/App.tsx
diff --git a/notto-client/src/assets/react.svg b/client/src/assets/react.svg
similarity index 100%
rename from notto-client/src/assets/react.svg
rename to client/src/assets/react.svg
diff --git a/notto-client/src/components/Home.tsx b/client/src/components/Home.tsx
similarity index 100%
rename from notto-client/src/components/Home.tsx
rename to client/src/components/Home.tsx
diff --git a/notto-client/src/components/Toaster.tsx b/client/src/components/Toaster.tsx
similarity index 100%
rename from notto-client/src/components/Toaster.tsx
rename to client/src/components/Toaster.tsx
diff --git a/notto-client/src/components/account/AccountMenu.tsx b/client/src/components/account/AccountMenu.tsx
similarity index 100%
rename from notto-client/src/components/account/AccountMenu.tsx
rename to client/src/components/account/AccountMenu.tsx
diff --git a/notto-client/src/components/account/AuthForm.tsx b/client/src/components/account/AuthForm.tsx
similarity index 100%
rename from notto-client/src/components/account/AuthForm.tsx
rename to client/src/components/account/AuthForm.tsx
diff --git a/notto-client/src/components/account/WorkspaceMenu.tsx b/client/src/components/account/WorkspaceMenu.tsx
similarity index 100%
rename from notto-client/src/components/account/WorkspaceMenu.tsx
rename to client/src/components/account/WorkspaceMenu.tsx
diff --git a/notto-client/src/components/icons/Icon.tsx b/client/src/components/icons/Icon.tsx
similarity index 100%
rename from notto-client/src/components/icons/Icon.tsx
rename to client/src/components/icons/Icon.tsx
diff --git a/notto-client/src/components/modals/ConflictModal.tsx b/client/src/components/modals/ConflictModal.tsx
similarity index 100%
rename from notto-client/src/components/modals/ConflictModal.tsx
rename to client/src/components/modals/ConflictModal.tsx
diff --git a/notto-client/src/components/modals/DeleteNoteConfirmModal.tsx b/client/src/components/modals/DeleteNoteConfirmModal.tsx
similarity index 100%
rename from notto-client/src/components/modals/DeleteNoteConfirmModal.tsx
rename to client/src/components/modals/DeleteNoteConfirmModal.tsx
diff --git a/notto-client/src/components/modals/LogoutWorkspaceConfirmModal.tsx b/client/src/components/modals/LogoutWorkspaceConfirmModal.tsx
similarity index 100%
rename from notto-client/src/components/modals/LogoutWorkspaceConfirmModal.tsx
rename to client/src/components/modals/LogoutWorkspaceConfirmModal.tsx
diff --git a/notto-client/src/components/note/FolderView.tsx b/client/src/components/note/FolderView.tsx
similarity index 100%
rename from notto-client/src/components/note/FolderView.tsx
rename to client/src/components/note/FolderView.tsx
diff --git a/notto-client/src/components/note/NoteEditor.css b/client/src/components/note/NoteEditor.css
similarity index 100%
rename from notto-client/src/components/note/NoteEditor.css
rename to client/src/components/note/NoteEditor.css
diff --git a/notto-client/src/components/note/NoteEditor.tsx b/client/src/components/note/NoteEditor.tsx
similarity index 100%
rename from notto-client/src/components/note/NoteEditor.tsx
rename to client/src/components/note/NoteEditor.tsx
diff --git a/notto-client/src/components/note/NoteHeader.tsx b/client/src/components/note/NoteHeader.tsx
similarity index 100%
rename from notto-client/src/components/note/NoteHeader.tsx
rename to client/src/components/note/NoteHeader.tsx
diff --git a/notto-client/src/components/sidebar/NoteTree.tsx b/client/src/components/sidebar/NoteTree.tsx
similarity index 100%
rename from notto-client/src/components/sidebar/NoteTree.tsx
rename to client/src/components/sidebar/NoteTree.tsx
diff --git a/notto-client/src/components/sidebar/Sidebar.tsx b/client/src/components/sidebar/Sidebar.tsx
similarity index 99%
rename from notto-client/src/components/sidebar/Sidebar.tsx
rename to client/src/components/sidebar/Sidebar.tsx
index 1bdb077..ceff882 100644
--- a/notto-client/src/components/sidebar/Sidebar.tsx
+++ b/client/src/components/sidebar/Sidebar.tsx
@@ -97,7 +97,7 @@ export default function Sidebar({
{/* Header */}
-
Notto
+
Nooto
{!showDeleted && (
<>
diff --git a/notto-client/src/lib/__tests__/errors.test.ts b/client/src/lib/__tests__/errors.test.ts
similarity index 100%
rename from notto-client/src/lib/__tests__/errors.test.ts
rename to client/src/lib/__tests__/errors.test.ts
diff --git a/notto-client/src/lib/errors.ts b/client/src/lib/errors.ts
similarity index 100%
rename from notto-client/src/lib/errors.ts
rename to client/src/lib/errors.ts
diff --git a/notto-client/src/main.tsx b/client/src/main.tsx
similarity index 100%
rename from notto-client/src/main.tsx
rename to client/src/main.tsx
diff --git a/notto-client/src/store/__tests__/general.test.ts b/client/src/store/__tests__/general.test.ts
similarity index 100%
rename from notto-client/src/store/__tests__/general.test.ts
rename to client/src/store/__tests__/general.test.ts
diff --git a/notto-client/src/store/__tests__/modals.test.ts b/client/src/store/__tests__/modals.test.ts
similarity index 100%
rename from notto-client/src/store/__tests__/modals.test.ts
rename to client/src/store/__tests__/modals.test.ts
diff --git a/notto-client/src/store/__tests__/toasts.test.ts b/client/src/store/__tests__/toasts.test.ts
similarity index 100%
rename from notto-client/src/store/__tests__/toasts.test.ts
rename to client/src/store/__tests__/toasts.test.ts
diff --git a/notto-client/src/store/general.tsx b/client/src/store/general.tsx
similarity index 100%
rename from notto-client/src/store/general.tsx
rename to client/src/store/general.tsx
diff --git a/notto-client/src/store/modals.tsx b/client/src/store/modals.tsx
similarity index 100%
rename from notto-client/src/store/modals.tsx
rename to client/src/store/modals.tsx
diff --git a/notto-client/src/store/toasts.ts b/client/src/store/toasts.ts
similarity index 100%
rename from notto-client/src/store/toasts.ts
rename to client/src/store/toasts.ts
diff --git a/notto-client/src/test/setup.ts b/client/src/test/setup.ts
similarity index 100%
rename from notto-client/src/test/setup.ts
rename to client/src/test/setup.ts
diff --git a/notto-client/src/types.ts b/client/src/types.ts
similarity index 100%
rename from notto-client/src/types.ts
rename to client/src/types.ts
diff --git a/notto-client/src/vite-env.d.ts b/client/src/vite-env.d.ts
similarity index 100%
rename from notto-client/src/vite-env.d.ts
rename to client/src/vite-env.d.ts
diff --git a/notto-client/tsconfig.json b/client/tsconfig.json
similarity index 100%
rename from notto-client/tsconfig.json
rename to client/tsconfig.json
diff --git a/notto-client/tsconfig.node.json b/client/tsconfig.node.json
similarity index 100%
rename from notto-client/tsconfig.node.json
rename to client/tsconfig.node.json
diff --git a/notto-client/vite.config.ts b/client/vite.config.ts
similarity index 100%
rename from notto-client/vite.config.ts
rename to client/vite.config.ts
diff --git a/notto-client/src-tauri/gen/android/app/src/main/res/values/strings.xml b/notto-client/src-tauri/gen/android/app/src/main/res/values/strings.xml
deleted file mode 100644
index 14be9e6..0000000
--- a/notto-client/src-tauri/gen/android/app/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
- notto
- notto
-
\ No newline at end of file
diff --git a/notto-server/Cargo.toml b/server/Cargo.toml
similarity index 94%
rename from notto-server/Cargo.toml
rename to server/Cargo.toml
index feee1ca..10d4771 100644
--- a/notto-server/Cargo.toml
+++ b/server/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "notto-server"
+name = "nooto-server"
version = "0.1.0"
edition = "2024"
diff --git a/notto-server/src/main.rs b/server/src/main.rs
similarity index 100%
rename from notto-server/src/main.rs
rename to server/src/main.rs
diff --git a/notto-server/src/schema.rs b/server/src/schema.rs
similarity index 100%
rename from notto-server/src/schema.rs
rename to server/src/schema.rs