From 85b541402a3f392d199419f80fcfb465d05e20be Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 26 Jun 2025 16:14:15 -0700 Subject: add intents --- android/app/src/main/AndroidManifest.xml | 82 +++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 28 deletions(-) (limited to 'android/app/src') diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 86de46b2..97c0e655 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -7,34 +7,60 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Date: Sun, 6 Jul 2025 23:10:37 -0700 Subject: nfc intents --- android/app/build.gradle | 4 +- android/app/src/main/AndroidManifest.xml | 119 +++++++------ .../app/src/main/java/io/coinos/MainActivity.java | 195 +++++++++++++-------- package.json | 2 +- 4 files changed, 198 insertions(+), 122 deletions(-) (limited to 'android/app/src') diff --git a/android/app/build.gradle b/android/app/build.gradle index 4d3dacf9..e419e70f 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -11,8 +11,8 @@ android { applicationId "io.coinos" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 7 - versionName "1.0.7" + versionCode 8 + versionName "1.0.8" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 97c0e655..72d7ccc0 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -7,60 +7,80 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> - - - - - - - + + + + + + + - - - - - - - + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + - - - - - - - - + + + + + + + + - diff --git a/android/app/src/main/java/io/coinos/MainActivity.java b/android/app/src/main/java/io/coinos/MainActivity.java index 7f710952..aaf59abe 100644 --- a/android/app/src/main/java/io/coinos/MainActivity.java +++ b/android/app/src/main/java/io/coinos/MainActivity.java @@ -2,80 +2,137 @@ package io.coinos; import com.getcapacitor.BridgeActivity; import com.getcapacitor.Bridge; -import com.getcapacitor.PluginCall; -import com.getcapacitor.PluginHandle; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.os.Parcelable; import android.webkit.CookieManager; import android.webkit.WebView; +import android.nfc.NdefMessage; +import android.nfc.NdefRecord; +import android.nfc.NfcAdapter; + +import java.nio.charset.Charset; +import java.util.Arrays; + public class MainActivity extends BridgeActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - WebView webView = bridge.getWebView(); - CookieManager cookieManager = CookieManager.getInstance(); - cookieManager.setAcceptCookie(true); - webView.getSettings().setJavaScriptEnabled(true); - webView.getSettings().setDomStorageEnabled(true); - - Intent intent = getIntent(); - if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) { - Uri data = intent.getData(); - if (data != null) { - String url = data.toString(); - Bridge bridge = getBridge(); - - if (bridge != null) { - String encodedUrl = Uri.encode(url); - String destinationUrl = "https://coinos.io/send/" + encodedUrl; - - bridge.getWebView().post(() -> { - bridge.getWebView().loadUrl(destinationUrl); - }); - } - } - } - } - - @Override - public void onNewIntent(Intent intent) { - super.onNewIntent(intent); - setIntent(intent); - if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) { - Uri data = intent.getData(); - if (data != null) { - String url = data.toString(); - - // Dispatch deep link when app is already open - Bridge bridge = getBridge(); - if (bridge != null) { - String encodedUrl = Uri.encode(url); - String destinationUrl = "https://coinos.io/send/" + encodedUrl; - - bridge.getWebView().post(() -> { - bridge.getWebView().loadUrl(destinationUrl); - }); - } - } - } - } - - @Override - public void onPause() { - super.onPause(); - CookieManager.getInstance().flush(); - } - - @Override - public void onBackPressed() { - WebView webView = getBridge().getWebView(); - if (webView.canGoBack()) { - webView.goBack(); - } else { - super.onBackPressed(); // Default behavior, which minimizes the app - } - } + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + WebView webView = bridge.getWebView(); + CookieManager cookieManager = CookieManager.getInstance(); + cookieManager.setAcceptCookie(true); + webView.getSettings().setJavaScriptEnabled(true); + webView.getSettings().setDomStorageEnabled(true); + + handleIntent(getIntent()); + } + + @Override + public void onNewIntent(Intent intent) { + super.onNewIntent(intent); + setIntent(intent); + handleIntent(intent); + } + + private void handleIntent(Intent intent) { + if (intent == null) return; + + String action = intent.getAction(); + Uri data = null; + + if (Intent.ACTION_VIEW.equals(action)) { + data = intent.getData(); + } else if ("android.nfc.action.NDEF_DISCOVERED".equals(action)) { + Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); + if (rawMsgs != null && rawMsgs.length > 0) { + NdefMessage ndefMessage = (NdefMessage) rawMsgs[0]; + for (NdefRecord record : ndefMessage.getRecords()) { + if (record.getTnf() == NdefRecord.TNF_WELL_KNOWN && + Arrays.equals(record.getType(), NdefRecord.RTD_URI)) { + + byte[] payload = record.getPayload(); + byte prefix = payload[0]; + String uriPrefix = resolveUriPrefix(prefix); + String uriBody = new String(Arrays.copyOfRange(payload, 1, payload.length), Charset.forName("UTF-8")); + data = Uri.parse(uriPrefix + uriBody); + break; + } + } + } + } + + if (data != null) { + String url = data.toString(); + Bridge bridge = getBridge(); + if (bridge != null) { + String encodedUrl = Uri.encode(url); + String destinationUrl = "https://coinos.io/send/" + encodedUrl; + + bridge.getWebView().post(() -> { + bridge.getWebView().loadUrl(destinationUrl); + }); + } + } + } + + private String resolveUriPrefix(byte prefix) { + switch (prefix) { + case 0x00: return ""; + case 0x01: return "http://www."; + case 0x02: return "https://www."; + case 0x03: return "http://"; + case 0x04: return "https://"; + case 0x05: return "tel:"; + case 0x06: return "mailto:"; + case 0x07: return "ftp://anonymous:anonymous@"; + case 0x08: return "ftp://ftp."; + case 0x09: return "ftps://"; + case 0x0A: return "sftp://"; + case 0x0B: return "smb://"; + case 0x0C: return "nfs://"; + case 0x0D: return "ftp://"; + case 0x0E: return "dav://"; + case 0x0F: return "news:"; + case 0x10: return "telnet://"; + case 0x11: return "imap:"; + case 0x12: return "rtsp://"; + case 0x13: return "urn:"; + case 0x14: return "pop:"; + case 0x15: return "sip:"; + case 0x16: return "sips:"; + case 0x17: return "tftp:"; + case 0x18: return "btspp://"; + case 0x19: return "btl2cap://"; + case 0x1A: return "btgoep://"; + case 0x1B: return "tcpobex://"; + case 0x1C: return "irdaobex://"; + case 0x1D: return "file://"; + case 0x1E: return "urn:epc:id:"; + case 0x1F: return "urn:epc:tag:"; + case 0x20: return "urn:epc:pat:"; + case 0x21: return "urn:epc:raw:"; + case 0x22: return "urn:epc:"; + case 0x23: return "urn:nfc:"; + default: return ""; + } + } + + @Override + public void onPause() { + super.onPause(); + CookieManager.getInstance().flush(); + } + + @Override + public void onBackPressed() { + WebView webView = getBridge().getWebView(); + if (webView.canGoBack()) { + webView.goBack(); + } else { + super.onBackPressed(); + } + } } diff --git a/package.json b/package.json index cec2b275..e7410f23 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "coinos", - "version": "1.0.7", + "version": "1.0.8", "devDependencies": { "@capacitor/android": "^6.2.0", "@capacitor/assets": "^3.0.5", -- cgit v1.2.3 From c0efcd94f37793348bc0cbe99a47e5fe8df4282a Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Tue, 8 Jul 2025 03:05:47 -0700 Subject: inset --- .../app/src/main/java/io/coinos/MainActivity.java | 17 ++++++++++++++++ capacitor.config.json | 23 +++++++++++----------- src/routes/(static)/register/+page.server.ts | 1 - src/routes/+layout.svelte | 11 +++++++++++ 4 files changed, 40 insertions(+), 12 deletions(-) (limited to 'android/app/src') diff --git a/android/app/src/main/java/io/coinos/MainActivity.java b/android/app/src/main/java/io/coinos/MainActivity.java index aaf59abe..791c89a9 100644 --- a/android/app/src/main/java/io/coinos/MainActivity.java +++ b/android/app/src/main/java/io/coinos/MainActivity.java @@ -1,5 +1,11 @@ package io.coinos; +import android.os.Build; +import android.view.View; +import android.view.WindowInsets; +import android.view.WindowManager; +import androidx.core.view.ViewCompat; + import com.getcapacitor.BridgeActivity; import com.getcapacitor.Bridge; import android.content.Intent; @@ -21,12 +27,23 @@ public class MainActivity extends BridgeActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + // Ensure the WebView doesn't overlap the system status bar + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); + } + WebView webView = bridge.getWebView(); CookieManager cookieManager = CookieManager.getInstance(); cookieManager.setAcceptCookie(true); webView.getSettings().setJavaScriptEnabled(true); webView.getSettings().setDomStorageEnabled(true); + // Ensure layout respects system window insets + ViewCompat.setOnApplyWindowInsetsListener(webView, (v, insets) -> { + v.setPadding(0, insets.getSystemWindowInsetTop(), 0, 0); + return insets; + }); + handleIntent(getIntent()); } diff --git a/capacitor.config.json b/capacitor.config.json index 585ff21c..a31c19db 100644 --- a/capacitor.config.json +++ b/capacitor.config.json @@ -1,13 +1,14 @@ { - "appId": "io.coinos", - "appName": "Coinos", - "server": { - "hostname": "coinos.io", - "url": "https://coinos.io/start" - }, - "android": { - "webContentsDebuggingEnabled": true, - "allowMixedContent": true, - "useBrowserHistory": true - } + "appId": "io.coinos", + "appName": "Coinos", + "server": { + "hostname": "coinos.io", + "url": "https://coinos.io/start" + }, + "android": { + "webContentsDebuggingEnabled": true, + "allowMixedContent": true, + "useBrowserHistory": true, + "immersive": false + } } diff --git a/src/routes/(static)/register/+page.server.ts b/src/routes/(static)/register/+page.server.ts index 8c6d6a8d..44aa69d3 100644 --- a/src/routes/(static)/register/+page.server.ts +++ b/src/routes/(static)/register/+page.server.ts @@ -21,6 +21,5 @@ export const actions = { const user = { picture, username, password }; await register(user, ip, cookies, loginRedirect); - redirect(303, loginRedirect || `/${user.username}`); }, }; diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index d25f570a..f2c567fa 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -61,4 +61,15 @@ --toastContainerLeft: calc(50vw - 8rem); --toastBackground: #292929; } + + main { + padding-top: constant(safe-area-inset-top); + padding-top: env(safe-area-inset-top); + } + + @supports not (padding-top: env(safe-area-inset-top)) { + main { + padding-top: 24px; + } + } -- cgit v1.2.3 From 503fa32f2453d76ed34d4d15f3321c981fc8f952 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Tue, 8 Jul 2025 03:35:34 -0700 Subject: inset --- .../app/src/main/java/io/coinos/MainActivity.java | 23 ++++++++----- android/app/src/main/res/layout/activity_main.xml | 13 ++++---- android/app/src/main/res/values/styles.xml | 13 +++++--- bun.lockb | Bin 289631 -> 290051 bytes package.json | 5 ++- src/routes/+layout.svelte | 37 +++++++++------------ 6 files changed, 50 insertions(+), 41 deletions(-) (limited to 'android/app/src') diff --git a/android/app/src/main/java/io/coinos/MainActivity.java b/android/app/src/main/java/io/coinos/MainActivity.java index 791c89a9..501d2e0f 100644 --- a/android/app/src/main/java/io/coinos/MainActivity.java +++ b/android/app/src/main/java/io/coinos/MainActivity.java @@ -8,6 +8,7 @@ import androidx.core.view.ViewCompat; import com.getcapacitor.BridgeActivity; import com.getcapacitor.Bridge; + import android.content.Intent; import android.net.Uri; import android.os.Bundle; @@ -25,25 +26,31 @@ import java.util.Arrays; public class MainActivity extends BridgeActivity { @Override protected void onCreate(Bundle savedInstanceState) { + // ✅ Let Capacitor inflate its layout and wire everything super.onCreate(savedInstanceState); - // Ensure the WebView doesn't overlap the system status bar + WebView webView = bridge.getWebView(); // This works *after* super.onCreate() + + // ✅ Ensure layout respects system bars if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE); } - WebView webView = bridge.getWebView(); + // ✅ Apply top inset padding if needed + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + webView.setOnApplyWindowInsetsListener((v, insets) -> { + v.setPadding(0, insets.getSystemWindowInsetTop(), 0, 0); + return insets.consumeSystemWindowInsets(); + }); + } + + // Other app setup CookieManager cookieManager = CookieManager.getInstance(); cookieManager.setAcceptCookie(true); webView.getSettings().setJavaScriptEnabled(true); webView.getSettings().setDomStorageEnabled(true); - // Ensure layout respects system window insets - ViewCompat.setOnApplyWindowInsetsListener(webView, (v, insets) -> { - v.setPadding(0, insets.getSystemWindowInsetTop(), 0, 0); - return insets; - }); - handleIntent(getIntent()); } diff --git a/android/app/src/main/res/layout/activity_main.xml b/android/app/src/main/res/layout/activity_main.xml index b5ad1387..3710e23b 100644 --- a/android/app/src/main/res/layout/activity_main.xml +++ b/android/app/src/main/res/layout/activity_main.xml @@ -1,12 +1,13 @@ - + android:fitsSystemWindows="true"> - + android:layout_height="match_parent" + android:fitsSystemWindows="true" /> + diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index be874e54..07128ac1 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -1,9 +1,7 @@ - - + - \ No newline at end of file + + diff --git a/bun.lockb b/bun.lockb index bcf4f106..2a601932 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 685cb7bb..a2241d3c 100644 --- a/package.json +++ b/package.json @@ -68,5 +68,8 @@ "lint": "prettier --check .", "format": "prettier --write ." }, - "type": "module" + "type": "module", + "dependencies": { + "cordova-plugin-android-notch": "^1.0.3" + } } diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 76db8abe..4317a6a2 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -16,16 +16,6 @@ ? `http://${PUBLIC_DOMAIN}` : `https://${PUBLIC_DOMAIN}`; - function getSafeInsetTop() { - const div = document.createElement("div"); - div.style.cssText = "position:absolute;top:0;padding-top:env(safe-area-inset-top);"; - document.body.appendChild(div); - const computed = getComputedStyle(div).paddingTop; - document.body.removeChild(div); - const px = parseInt(computed, 10); - return isNaN(px) ? 24 : px; - } - onMount(() => { if (!browser) return; @@ -35,11 +25,18 @@ $installPrompt = event; }); - // Fix: Apply top padding manually for Android WebView - const insetTop = getSafeInsetTop(); - const main = document.querySelector("main"); - if (main && insetTop > 0) { - main.style.paddingTop = `${insetTop}px`; + if (typeof window.AndroidNotch !== "undefined") { + window.AndroidNotch.getInsetTop( + (px) => { + document.documentElement.style.setProperty( + "--safe-area-inset-top", + px + "px", + ); + }, + (err) => { + console.error("Failed to get notch inset:", err); + }, + ); } }); @@ -75,15 +72,11 @@ --toastContainerBottom: 8rem; --toastContainerLeft: calc(50vw - 8rem); --toastBackground: #292929; - } - main { - padding-top: env(safe-area-inset-top, 24px); + --safe-area-inset-top: 24px; } - @supports not (padding-top: env(safe-area-inset-top)) { - main { - padding-top: 24px; - } + main { + padding-top: var(--safe-area-inset-top); } -- cgit v1.2.3 From 5b458624745c7ea80d1e63c9a6ef77075763ff5f Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 10 Jul 2025 12:36:50 -0700 Subject: user onboarding --- .../app/src/main/java/io/coinos/MainActivity.java | 5 ++ .../java/io/coinos/nfcwriter/NfcWriterPlugin.java | 62 ++++++++++++++++++++++ capacitor.config.json | 7 ++- src/lib/utils.ts | 2 +- src/locales/en.json | 7 ++- src/routes/(app)/+layout.svelte | 45 ++++++++++------ src/routes/(app)/[username]/(profile)/+page.svelte | 22 +++++++- src/routes/(app)/fund/[id]/sweep/+page.server.ts | 10 ++-- src/routes/(app)/fund/[id]/sweep/+page.svelte | 6 ++- src/routes/(app)/funder/+page.svelte | 55 +++++++++++++++++++ src/routes/(app)/invoice/[id]/tip/+page.server.ts | 28 +++++----- src/routes/(app)/settings/profile/+page.svelte | 16 +++++- src/routes/(app)/settings/security/+page.svelte | 12 ----- 13 files changed, 225 insertions(+), 52 deletions(-) create mode 100644 android/app/src/main/java/io/coinos/nfcwriter/NfcWriterPlugin.java create mode 100644 src/routes/(app)/funder/+page.svelte (limited to 'android/app/src') diff --git a/android/app/src/main/java/io/coinos/MainActivity.java b/android/app/src/main/java/io/coinos/MainActivity.java index 501d2e0f..271ee363 100644 --- a/android/app/src/main/java/io/coinos/MainActivity.java +++ b/android/app/src/main/java/io/coinos/MainActivity.java @@ -23,11 +23,16 @@ import android.nfc.NfcAdapter; import java.nio.charset.Charset; import java.util.Arrays; +import io.coinos.nfcwriter.NfcWriterPlugin; + public class MainActivity extends BridgeActivity { + private NfcAdapter nfcAdapter; + @Override protected void onCreate(Bundle savedInstanceState) { // ✅ Let Capacitor inflate its layout and wire everything super.onCreate(savedInstanceState); + registerPlugin(NfcWriterPlugin.class); WebView webView = bridge.getWebView(); // This works *after* super.onCreate() diff --git a/android/app/src/main/java/io/coinos/nfcwriter/NfcWriterPlugin.java b/android/app/src/main/java/io/coinos/nfcwriter/NfcWriterPlugin.java new file mode 100644 index 00000000..d2954e9b --- /dev/null +++ b/android/app/src/main/java/io/coinos/nfcwriter/NfcWriterPlugin.java @@ -0,0 +1,62 @@ +// src/android/NfcWriterPlugin.java +package io.coinos.nfcwriter; + +import android.nfc.NfcAdapter; +import android.nfc.Tag; +import android.nfc.NfcAdapter.ReaderCallback; +import android.os.Bundle; +import android.util.Log; + +import com.getcapacitor.Plugin; +import com.getcapacitor.PluginCall; +import com.getcapacitor.PluginMethod; +import com.getcapacitor.annotation.CapacitorPlugin; + +@CapacitorPlugin(name = "NfcWriter") +public class NfcWriterPlugin extends Plugin { + private NfcAdapter nfcAdapter; + + @Override + public void load() { + super.load(); + nfcAdapter = NfcAdapter.getDefaultAdapter(getContext()); + } + + @PluginMethod + public void enableExclusiveNfcMode(PluginCall call) { + if (nfcAdapter == null) { + call.reject("NFC adapter not available"); + return; + } + + nfcAdapter.enableReaderMode( + getActivity(), + new ReaderCallback() { + @Override + public void onTagDiscovered(Tag tag) { + Log.d("NfcWriter", "Tag discovered"); + bridge.getWebView().post(() -> { + bridge.getWebView().evaluateJavascript( + "window.dispatchEvent(new CustomEvent('nativeNfcTagDiscovered'))", + null + ); + }); + } + }, + NfcAdapter.FLAG_READER_NFC_A | + NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK | + NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS, + null + ); + + call.resolve(); + } + + @PluginMethod + public void disableExclusiveNfcMode(PluginCall call) { + if (nfcAdapter != null) { + nfcAdapter.disableReaderMode(getActivity()); + } + call.resolve(); + } +} diff --git a/capacitor.config.json b/capacitor.config.json index a31c19db..99458def 100644 --- a/capacitor.config.json +++ b/capacitor.config.json @@ -2,13 +2,16 @@ "appId": "io.coinos", "appName": "Coinos", "server": { - "hostname": "coinos.io", - "url": "https://coinos.io/start" + "hostname": "dev.coinos.io", + "url": "https://dev.coinos.io/start" }, "android": { "webContentsDebuggingEnabled": true, "allowMixedContent": true, "useBrowserHistory": true, "immersive": false + }, + "plugins": { + "NfcWriter": {} } } diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 31d93fde..28a219e1 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -486,5 +486,5 @@ export const register = async (user, ip, cookies, loginRedirect) => { }); if (error) return svelteFail(400, { error }); - redirect(303, loginRedirect || `/${user.username}`); + redirect(303, loginRedirect || `/${user.username}`); }; diff --git a/src/locales/en.json b/src/locales/en.json index 922d24b3..88de69da 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -350,7 +350,12 @@ "locale": "Language", "username": "Username", "email": "Email", - "newPassword": "Change Password", + "newPassword": "New Password", + "newPasswordDesc": "(Leave blank to keep unchanged)", + "yourUsername": "Your username is", + "yourPassword": "and your password is", + "welcome": "Welcome!", + "clickBelow": "Click below to finish setting up your account", "about": "About", "aboutPlaceholder": "A little something about you or your business address and hours", "emailNotifications": "Email Notifications", diff --git a/src/routes/(app)/+layout.svelte b/src/routes/(app)/+layout.svelte index af4dbf2c..830e5291 100644 --- a/src/routes/(app)/+layout.svelte +++ b/src/routes/(app)/+layout.svelte @@ -46,22 +46,35 @@ checkSocket(); $pin = getCookie("pin"); - if (window.NDEFReader && user.nfc) { - try { - $ndef = new NDEFReader(); - await $ndef.scan(); - - $ndef.addEventListener("readingerror", (e) => { - console.log("nfc error", e); - }); - - $ndef.addEventListener("reading", ({ message, serialNumber }) => { - goto(`/send/${message}`); - }); - } catch (error) { - console.log("Argh! " + error); - } - } + // if (window.NDEFReader) { + // try { + // $ndef = new NDEFReader(); + // await $ndef.scan(); + // + // $ndef.addEventListener("readingerror", (e) => { + // console.log("nfc error", e); + // }); + // + // $ndef.addEventListener("reading", ({ message, serialNumber }) => { + // console.log("MESSAGE", message); + // + // const record = message.records[0]; + // + // if (record.recordType === "url") { + // const textDecoder = new TextDecoder(); + // const url = textDecoder.decode(record.data); + // console.log("URL:", url); + // + // // Navigate to the URL or use it however you want + // goto(`/send/${encodeURIComponent(url)}`); + // } else { + // console.error("Unsupported record type:", record.recordType); + // } + // }); + // } catch (error) { + // console.log("Argh! " + error); + // } + // } } }); diff --git a/src/routes/(app)/[username]/(profile)/+page.svelte b/src/routes/(app)/[username]/(profile)/+page.svelte index d064c3a9..31320197 100644 --- a/src/routes/(app)/[username]/(profile)/+page.svelte +++ b/src/routes/(app)/[username]/(profile)/+page.svelte @@ -6,7 +6,7 @@ import Account from "$comp/Account.svelte"; import Balance from "$comp/Balance.svelte"; import { t } from "$lib/translations"; - import { installPrompt } from "$lib/store"; + import { installPrompt, password } from "$lib/store"; import { afterNavigate, preloadData } from "$app/navigation"; import { page } from "$app/stores"; @@ -32,6 +32,24 @@
+ {#if user?.fresh} +
+

{$t("user.settings.welcome")}

+
+ {$t("user.settings.yourUsername")} {user?.username} + {#if $password} + {$t("user.settings.yourPassword")} + {$password}{/if} +
+ +
{$t("user.settings.clickBelow")}
+ + + + Settings +
+ {/if} {#if user?.id && user.id === subject.id}
{#each accounts as account, i} @@ -55,6 +73,8 @@ {/if}
+ +
{#if user?.username !== subject.username && (!subject.anon || subject.lud16)} + import { onMount } from "svelte"; + import { password } from "$lib/store"; import Amount from "$comp/Amount.svelte"; import Success from "$comp/Success.svelte"; import { scale } from "svelte/transition"; @@ -9,9 +11,11 @@ let { data } = $props(); - let { amount, id, user, rate, rates } = data; + let { amount, id, user, rate, rates, password: pw } = data; let { currency } = user; let locale = $derived(loc(user)); + + onMount(() => ($password = pw));
diff --git a/src/routes/(app)/funder/+page.svelte b/src/routes/(app)/funder/+page.svelte new file mode 100644 index 00000000..e6549360 --- /dev/null +++ b/src/routes/(app)/funder/+page.svelte @@ -0,0 +1,55 @@ + + +HI + +{#if here}HERE{/if} +{#if ready}go{/if} +{#if success}done{/if} diff --git a/src/routes/(app)/invoice/[id]/tip/+page.server.ts b/src/routes/(app)/invoice/[id]/tip/+page.server.ts index de24c639..286d7c35 100644 --- a/src/routes/(app)/invoice/[id]/tip/+page.server.ts +++ b/src/routes/(app)/invoice/[id]/tip/+page.server.ts @@ -8,20 +8,22 @@ export async function load({ cookies, parent }) { let { invoice, subject, user } = await parent(); if (!invoice.amount) redirect(307, `/invoice/${invoice.id}`); - const trust = await get("/trust", auth(cookies)); - const trusted = trust.includes(invoice.uid); - if (trusted) { - if (invoice.prompt && invoice.tip === null && user.tip > 0) { - invoice.tip = Math.round(invoice.amount * (user.tip / 100)); - invoice = await post( - "/invoice", - { invoice, user: subject }, - auth(cookies), - ); - } + if (user) { + const trust = await get("/trust", auth(cookies)); + const trusted = trust.includes(invoice.uid); + if (trusted) { + if (invoice.prompt && invoice.tip === null && user.tip > 0) { + invoice.tip = Math.round(invoice.amount * (user.tip / 100)); + invoice = await post( + "/invoice", + { invoice, user: subject }, + auth(cookies), + ); + } - const p = await post("/payments", invoice, auth(cookies)); - redirect(307, `/sent/${p.id}`); + const p = await post("/payments", invoice, auth(cookies)); + redirect(307, `/sent/${p.id}`); + } } const rate = rates[subject?.currency]; diff --git a/src/routes/(app)/settings/profile/+page.svelte b/src/routes/(app)/settings/profile/+page.svelte index bee50d39..ec9855d0 100644 --- a/src/routes/(app)/settings/profile/+page.svelte +++ b/src/routes/(app)/settings/profile/+page.svelte @@ -3,16 +3,18 @@ import { avatar, banner as bannerStore } from "$lib/store"; import { t } from "$lib/translations"; import { page } from "$app/stores"; + import PasswordInput from "$comp/PasswordInput.svelte"; let { data } = $props(); let { user } = $derived(data); let { id } = user; - let { about, banner, picture, display, username } = - $state(user); + let { about, banner, picture, display, username } = $state(user); let avatarFile, avatarInput = $state(), bannerFile, + password = $state(), + revealPassword = $state(), bannerInput = $state(); let selectAvatar = () => avatarInput.click(); @@ -64,6 +66,16 @@
+ + +
+ + + +
+
- - -
- - - -