Compare commits

...

829 Commits

Author SHA1 Message Date
Jon Staab 53954aae89 classnames tweak 2026-04-17 16:06:00 -07:00
userAdityaa 24aa62a503 chore: carify Pomade login errors with actionable invalid vs network messaging (#233)
Co-authored-by: userAdityaa <aditya.chaudhary1558@gmail.com>
Co-committed-by: userAdityaa <aditya.chaudhary1558@gmail.com>
2026-04-17 23:00:03 +00:00
Jon Staab 2618bb9c63 Fix centered layout 2026-04-17 14:58:59 -07:00
Prat_09 32a31045ef fix: Improve toggle switch placement in settings screen (#208) (#232)
Co-authored-by: Pratyush Mohanty <prat_09@noreply.coracle.social>
Co-committed-by: Pratyush Mohanty <prat_09@noreply.coracle.social>
2026-04-17 21:58:52 +00:00
DeveshSingh 56edad77a8 fix: added logic for password requirements on signup (#230)
Co-authored-by: deveshanim3 <deveshsingh6986@gmail.com>
Co-committed-by: deveshanim3 <deveshsingh6986@gmail.com>
2026-04-17 19:43:27 +00:00
priyanshu_bharti fdb604e350 Use type=email for signup/login email inputs (#225) (#228)
Co-authored-by: Priyanshubhartistm <bhartipriyanshustm@gmail.com>
Co-committed-by: Priyanshubhartistm <bhartipriyanshustm@gmail.com>
2026-04-17 18:55:04 +00:00
DeveshSingh 3c66dfd83c fix/wrong-message-offline (#222)
Co-authored-by: deveshanim3 <deveshsingh6986@gmail.com>
Co-committed-by: deveshanim3 <deveshsingh6986@gmail.com>
2026-04-17 18:24:55 +00:00
userAdityaa 81633b0a1e fix: vertical alignment of emoji and overflow buttons in shared event action row (#219)
Co-authored-by: userAdityaa <aditya.chaudhary1558@gmail.com>
Co-committed-by: userAdityaa <aditya.chaudhary1558@gmail.com>
2026-04-17 15:22:40 +00:00
Khushvendra 4a967de184 fix(chat): suppress programmatic scroll while user is scrolling (#132) (#216)
Co-authored-by: 1amKhush <khushvendras99@gmail.com>
Co-committed-by: 1amKhush <khushvendras99@gmail.com>
2026-04-16 23:20:17 +00:00
DeveshSingh 59961cbdb5 fix: supported nip overflow in SpaceRelayStatus.svelte (#215)
Co-authored-by: deveshanim3 <deveshsingh6986@gmail.com>
Co-committed-by: deveshanim3 <deveshsingh6986@gmail.com>
2026-04-16 21:36:14 +00:00
Jon Staab 95d9d8bf23 Bump version 2026-04-16 14:10:50 -07:00
Jon Staab 2fd9741a2b Fix safe area inset for chat fab
Docker / build-and-push-image (push) Successful in 16m42s
2026-04-16 14:08:25 -07:00
Jon Staab fe9c325580 Update universal links 2026-04-16 13:50:13 -07:00
Jon Staab 61e93d4071 Update changelog, bump version
Docker / build-and-push-image (push) Successful in 19m16s
2026-04-16 11:40:24 -07:00
Jon Staab 1e4a4e43dc remove dead virtualization code 2026-04-16 11:39:11 -07:00
Jon Staab e1a7b051bd Use welshman kinds 2026-04-16 11:34:59 -07:00
sakshamjain 7a7af58f5c feat: add native share support for space invites 2026-04-16 10:16:12 -07:00
Jon Staab 016ae86d50 Stop sending duplicate requests per room 2026-04-16 10:03:01 -07:00
Jon Staab 2bff060a5e Add thumbnail url 2026-04-16 10:03:01 -07:00
userAdityaa 68231504d0 fix: modal close button stacking above emoji picker on mobile (#211)
Co-authored-by: userAdityaa <aditya.chaudhary1558@gmail.com>
Co-committed-by: userAdityaa <aditya.chaudhary1558@gmail.com>
2026-04-16 15:38:25 +00:00
DeveshSingh 0658a8ee44 bug: fixed calender modal stacking issue (#209)
Co-authored-by: deveshanim3 <deveshsingh6986@gmail.com>
Co-committed-by: deveshanim3 <deveshsingh6986@gmail.com>
2026-04-16 14:55:37 +00:00
priyanshu_bharti 43fb3d35e6 Fix #202 slow-network invite timeout handling (#207)
Co-authored-by: Priyanshubhartistm <bhartipriyanshustm@gmail.com>
Co-committed-by: Priyanshubhartistm <bhartipriyanshustm@gmail.com>
2026-04-15 22:01:00 +00:00
Khushvendra 4cc1cc95ca Fix voice call cold-start timeout and preserve custom timeout message (#174) (#203)
Co-authored-by: 1amKhush <khushvendras99@gmail.com>
Co-committed-by: 1amKhush <khushvendras99@gmail.com>
2026-04-15 20:37:03 +00:00
Prat_09 964ef441ec Update relay description (#195) (#197)
Co-authored-by: Pratyush Mohanty <prat_09@noreply.coracle.social>
Co-committed-by: Pratyush Mohanty <prat_09@noreply.coracle.social>
2026-04-14 15:09:46 +00:00
priyanshu_bharti 796f37d320 Make space reordering discoverable with smoother drag animation (#171)
Co-authored-by: Priyanshu Bharti <bhartipriyanshustm@gmail.com>
Co-committed-by: Priyanshu Bharti <bhartipriyanshustm@gmail.com>
2026-04-13 22:38:02 +00:00
nayan9617 b46fd94578 Use relay-provided member lists as source of truth (#191)
Co-authored-by: Nayan Patidar <nayan9617@noreply.coracle.social>
Co-committed-by: Nayan Patidar <nayan9617@noreply.coracle.social>
2026-04-13 21:12:49 +00:00
Jon Staab bdc8e75640 Fix search input width 2026-04-13 12:08:11 -07:00
Jon Staab ef08821796 remove VirtualItem 2026-04-13 10:35:26 -07:00
Jon Staab 9f386f6968 remove redundant room syncing logic 2026-04-11 10:20:50 -07:00
Khushvendra ec0b6a99e2 add room mentions and clickable room/relay refs 2026-04-11 10:13:23 -07:00
Khushvendra f6d9e52c6e fix: support native clipboard image paste on mobile (#181)
Co-authored-by: Khushvendra <khushvendras99@gmail.com>
Co-committed-by: Khushvendra <khushvendras99@gmail.com>
2026-04-11 16:38:06 +00:00
Jon Staab 90f86b833d Handle quotes in RoomItem. Fixes #188 2026-04-10 15:27:36 -07:00
userAdityaa 29bb33c26c publish kind 9 quote after room content creation for cross-client interoperability 2026-04-10 14:20:24 -07:00
Jon Staab c740bd21d4 Fix space page layout on Android by adding visible prop to SecondaryNav 2026-04-10 13:26:14 -07:00
Jon Staab 1d92709c76 perf: task-fix-list-virtualization changes 2026-04-10 12:44:01 -07:00
Jon Staab a42e1df1a7 Fix feed pagination logic 2026-04-10 12:40:28 -07:00
Jon Staab e33beee17d perf: task-fix-raf-derived-to-effect changes 2026-04-10 12:30:25 -07:00
Jon Staab b10ea04cb3 Fix Android push fallback: show all notifications, retry on failure 2026-04-10 12:23:32 -07:00
priyanshu_bharti e8c94177ca Support Aegis URL scheme for NIP-46 login (#161)
Co-authored-by: Priyanshubhartistm <bhartipriyanshustm@gmail.com>
Co-committed-by: Priyanshubhartistm <bhartipriyanshustm@gmail.com>
2026-04-10 19:04:34 +00:00
Jon Staab f1f2083c88 Remove unnecessary snapshots, format 2026-04-10 11:09:26 -07:00
Jon Staab f42889c3c2 Improve performance #182:
increase profile timer and chat search throttle delays
reduce GC pressure in derived stores
use requestIdleCallback for non-critical storage writes
batch repository update processing in feeds
2026-04-10 10:39:38 -07:00
Jon Staab a75e1f96eb Add .claude to gitignore 2026-04-10 10:14:01 -07:00
priyanshu_bharti 85c5293082 Raise message size limit in chat (#186)
Co-authored-by: Priyanshubhartistm <bhartipriyanshustm@gmail.com>
Co-committed-by: Priyanshubhartistm <bhartipriyanshustm@gmail.com>
2026-04-10 16:37:23 +00:00
Jon Staab 37efa6a62c Bump pomade 2026-04-10 09:24:22 -07:00
userAdityaa 1d5f91fb6c fix: realtime updates for room members and admins (#178)
Co-authored-by: userAdityaa <aditya.chaudhary1558@gmail.com>
Co-committed-by: userAdityaa <aditya.chaudhary1558@gmail.com>
2026-04-09 21:05:30 +00:00
userAdityaa ef18655776 make close button / backdrop work on direct invite link page (#177)
Co-authored-by: userAdityaa <aditya.chaudhary1558@gmail.com>
Co-committed-by: userAdityaa <aditya.chaudhary1558@gmail.com>
2026-04-09 20:03:08 +00:00
sakshamjain b786e858d9 correct inverted arrow icon in advanced section toggle (#180)
Co-authored-by: Saksham Jain <reach2saksham2004@gmail.com>
Co-committed-by: Saksham Jain <reach2saksham2004@gmail.com>
2026-04-09 19:57:15 +00:00
mplorentz f4ebc4e99e Video in calls (#135)
#135

This PR adds basic video functionality to our voice rooms. Again I followed the Discord UX for inspiration, so all video calls start as voice-only calls that gracefully upgrade (and downgrade) when someone turns on a video or starts screen sharing.

When a video feed is detected the Room page will change to display a grid of feeds. The grid logic is very basic, that's definitely an area to improve in the future. You can open the chat part of the room with a new button on the VoiceWidget - on the desktop layout this creates a split view with video on the left and chat on the right, but on mobile it switches to chat fullscreen. I also added a little pin icon you can use to focus on a single video feed (useful for screen sharing). There is a lot of tailwind I don't understand here, but it seems to work well enough.

I moved voice.ts into a new `call` folder and moved some of its stores into `call/stores.ts` which allowed me to keep most of the video logic in `call/video.ts`. It's not a perfect encapsulation as voice.ts does subscribe to some of the hooks for the livekit calls and passes some of the signals onto `video.ts`. This could probably be broken up better but for this PR I'd rather not focus on making it perfect if that's ok. Partly for the sake of time but also because I envision another PR that renames/reorganizes things and I think a larger UX evaluation is necessary and should include real user feedback. I'm not confident tha""t the Voice Room concept as a whole will stick going forward. Maybe all rooms in a livekit enabled server should be able to host a call (like a slack huddle), maybe users want to be able to schedule calls as events, or even have them start with an ad-hoc set of participants completely outside of a NIP-29 group, etc.

Co-authored-by: mplorentz <mplorentz@noreply.gitea.coracle.social>
Reviewed-on: #135
Co-authored-by: Matt Lorentz <mplorentz@noreply.coracle.social>
Co-committed-by: Matt Lorentz <mplorentz@noreply.coracle.social>
2026-04-08 17:10:20 +00:00
Jon Staab 65ca8a7fd8 Remove follow graph building 2026-04-08 09:46:56 -07:00
nayan9617 7f1e98dcb2 Fix fallback pull race after abort (#167)
Co-authored-by: nayan9617 <nayanp4925@gmail.com>
Co-committed-by: nayan9617 <nayanp4925@gmail.com>
2026-04-08 16:43:04 +00:00
priyanshu_bharti 4c19ee823b 73-video-thumbnails (#142)
This PR implements video thumbnails for `.mov`, `.webm`, and `.mp4` files in the `ContentLinkBlock` component.

Changes:
- Added the `poster` attribute to the `<video>` tag.
- Set the poster source to `{url}#t=1` to capture a clear preview frame at the 1-second mark.
- Verified locally that thumbnails are now correctly displayed instead of a black/empty box.

Closes #73

Reviewed-on: #142
Co-authored-by: Priyanshubhartistm <bhartipriyanshustm@gmail.com>
Co-committed-by: Priyanshubhartistm <bhartipriyanshustm@gmail.com>
2026-04-08 16:07:11 +00:00
Jon Staab 8e2dd8b278 Upgrade daisyui/tailwind 2026-04-07 15:31:35 -07:00
Jon Staab 8d35b3aad2 Chat tweaks 2026-04-07 10:40:45 -07:00
Prat_09 613cad31c0 add start chat FAB (#152)
Co-authored-by: Pratyush Mohanty <prat_09@noreply.coracle.social>
Co-committed-by: Pratyush Mohanty <prat_09@noreply.coracle.social>
2026-04-07 17:02:40 +00:00
Jon Staab 3779a90f26 Tweak to chat item menu buttons 2026-04-07 09:51:25 -07:00
theAnuragMishra 7470f28f31 fix spacing around messages (#159)
Co-authored-by: theAnuragMishra <theanuragmishra@noreply.coracle.social>
Co-committed-by: theAnuragMishra <theanuragmishra@noreply.coracle.social>
2026-04-07 16:50:53 +00:00
hodlbod 17fb4e780b Clean up drafts implementation (#164) 2026-04-07 13:06:29 +00:00
userAdityaa 30c2a6ef79 persist drafts in memory (#155)
Co-authored-by: userAdityaa <aditya.chaudhary1558@gmail.com>
Co-committed-by: userAdityaa <aditya.chaudhary1558@gmail.com>
2026-04-07 12:06:29 +00:00
Jon Staab 0547e9513f Small css tweak 2026-04-06 09:21:59 -07:00
nayan9617 70e5172f1b fix/tooltip-clipping (#156)
Co-authored-by: nayan9617 <nayanp4925@gmail.com>
Co-committed-by: nayan9617 <nayanp4925@gmail.com>
2026-04-06 16:14:08 +00:00
Jon Staab 61c568a112 Formatting 2026-04-06 09:09:01 -07:00
Jon Staab ae2ba6f44d Tweak toast close button 2026-04-06 09:08:26 -07:00
Jon Staab f84006fbe4 Tweak button on profile page 2026-04-06 09:08:26 -07:00
priyanshu_bharti fed34a2747 show space name on hover in primary nav (#129) (#136)
Co-authored-by: Priyanshubhartistm <bhartipriyanshustm@gmail.com>
Co-committed-by: Priyanshubhartistm <bhartipriyanshustm@gmail.com>
2026-04-06 16:08:02 +00:00
userAdityaa 80df16f97b feat: redesign toast notifications for UX (#148)
Co-authored-by: userAdityaa <aditya.chaudhary1558@gmail.com>
Co-committed-by: userAdityaa <aditya.chaudhary1558@gmail.com>
2026-04-04 16:45:49 +00:00
junaiddshaukat 18cb245599 Remove room/space leave indications (#149)
Co-authored-by: junaiddshaukat <junaiddshaukat@noreply.coracle.social>
Co-committed-by: junaiddshaukat <junaiddshaukat@noreply.coracle.social>
2026-04-04 16:28:11 +00:00
Jon Staab fd6cc84be6 Simplify chat compose layout 2026-04-04 09:02:52 -07:00
Jon Staab 9311cab3b2 Move away from fixed positioned page elements because they act squirrely on android 2026-04-03 17:16:47 -07:00
userAdityaa fceccf47be fix(ui): hide report badge for non-admin users (#147)
Co-authored-by: userAdityaa <aditya.chaudhary1558@gmail.com>
Co-committed-by: userAdityaa <aditya.chaudhary1558@gmail.com>
2026-04-03 23:54:20 +00:00
Jon Staab fe20fbfd28 Add polls 2026-04-03 10:56:00 -07:00
junaiddshaukat 4f3a2a1660 Add space search to recent activity page (#59) (#119)
Co-authored-by: junaiddshaukat <junaiddshaukat@noreply.coracle.social>
Co-committed-by: junaiddshaukat <junaiddshaukat@noreply.coracle.social>
2026-04-03 16:58:35 +00:00
Jon Staab 1c8457a4bf Fix notification badge on mobile nav 2026-04-02 16:47:32 -07:00
Jon Staab 8710043a02 Fix env conventions again 2026-04-02 14:01:09 -07:00
Jon Staab dc46b42cb6 Fix platform logo 2026-04-02 13:49:01 -07:00
Jon Staab 2f1972e70a Add contributing file 2026-04-02 13:31:37 -07:00
mplorentz c5fcf12165 Fix error toast when failing to join room. (#113)
Co-authored-by: Matt Lorentz <mplorentz@noreply.coracle.social>
Co-committed-by: Matt Lorentz <mplorentz@noreply.coracle.social>
2026-04-02 19:35:46 +00:00
mplorentz 61ed632579 Change audio devices in call (#112)
Co-authored-by: Matt Lorentz <mplorentz@noreply.coracle.social>
Co-committed-by: Matt Lorentz <mplorentz@noreply.coracle.social>
2026-04-02 19:33:48 +00:00
Jon Staab 86f4b75c52 Merge subs to avoid hitting limits 2026-04-02 11:49:26 -07:00
bhavishy2801 b26ab916d5 feat: use NIP-50 relay-side search with scope selection (#114)
Co-authored-by: Bhavishy <bhavishyrocker2801@gmail.com>
Co-committed-by: Bhavishy <bhavishyrocker2801@gmail.com>
2026-04-02 18:49:18 +00:00
nayan9617 c882198206 fix: respect VITE_PLATFORM_LOGO with fallback (#116)
Co-authored-by: nayan9617 <nayanp4925@gmail.com>
Co-committed-by: nayan9617 <nayanp4925@gmail.com>
2026-04-02 17:52:44 +00:00
Jon Staab 4aef27ffd5 Fix xcode version
Docker / build-and-push-image (push) Successful in 15m54s
2026-04-02 07:08:16 -07:00
Jon Staab cf4e3f5fc6 Bump version 2026-04-02 07:05:34 -07:00
Jon Staab 57eb919c83 Bump welshman to fix poll behavior
Docker / build-and-push-image (push) Has been cancelled
2026-04-02 07:02:57 -07:00
Jon Staab 85cfaf2bc9 Remove redundant join space button 2026-04-02 06:29:37 -07:00
Jon Staab 25a69a8191 Small tweaks 2026-04-01 14:07:29 -07:00
Jon Staab 6feeb23b1f Bump welshman 2026-04-01 11:39:05 -07:00
Jon Staab 4b92ffe3c5 remove duplicate spaces button 2026-04-01 11:33:56 -07:00
Jon Staab 823a9c3271 Combine discover and space list into a single page 2026-03-31 14:24:09 -07:00
Jon Staab fe89df2aa3 Fix some chat related bugs
Docker / build-and-push-image (push) Successful in 22m43s
2026-03-31 11:25:59 -07:00
Jon Staab 97ff8ff802 Bump version
Docker / build-and-push-image (push) Successful in 22m2s
2026-03-31 09:55:04 -07:00
Jon Staab a10a9e7043 Bump pomade 2026-03-31 09:53:30 -07:00
Jon Staab 4f42abc2ff Bump version
Docker / build-and-push-image (push) Successful in 17m16s
2026-03-30 15:22:01 -07:00
Jon Staab fe042c88b8 Apply safe area insets to new messages button 2026-03-30 15:15:41 -07:00
Jon Staab 55e3a31b61 Show notifications on non-nip29 chat 2026-03-30 14:29:24 -07:00
Jon Staab 5760be4313 Add back button to chat detail 2026-03-30 14:24:40 -07:00
Jon Staab 2fd7556a52 Fix new messages button, improve room load 2026-03-30 14:20:30 -07:00
Jon Staab e8ed9cd379 Fix chat new messages fixed button 2026-03-30 13:22:22 -07:00
Jon Staab eeeb3c96d2 Bump welshman 2026-03-30 11:46:12 -07:00
Jon Staab 2da5dee6bd Add pow to wrapped messages 2026-03-30 11:46:12 -07:00
Jon Staab a66193ff45 Fix some display bugs 2026-03-30 11:46:12 -07:00
Jon Staab 55131ba7ce Remove replaceState from SpaceMenu since we're never in a drawer any more 2026-03-30 11:46:12 -07:00
Jon Staab df6282d2ba Fix nav overflow on mobile 2026-03-30 11:46:12 -07:00
Jon Staab 6ebe792ce5 Show notification badge on voice room item 2026-03-30 11:46:11 -07:00
Jon Staab 6c9bdb2ccd Detect blossom support using supported_nips 2026-03-30 11:46:11 -07:00
Jon Staab bc94c705f3 Make space syncing more robust 2026-03-30 11:46:11 -07:00
Jon Staab 2b9b4da2cc Add all rooms to notifications 2026-03-30 11:46:11 -07:00
Jon Staab 090070d1f9 Add dm relay 2026-03-30 11:46:11 -07:00
mplorentz 16a73f27c9 Add a dialog before joining voice rooms (#109)
After using the voice rooms more since we removed the option for voice-only rooms I think you were right to suggest a dialog box before joining rooms. It felt far to clunky to have to join the voice call any time you just wanted to try to view room members, edit room settings, or just view the recent text chat.

This adds a dialog that allows the user to decline to join the call but still access the text part of the room along with associated settings and controls. It also acts as another confirmation step before turning on the user's microphone, and allows them to choose an audio input so they don't have to mess with the (generally terrible) browser controls for doing so. We should probably have controls to change your audio input and output from within the call as well, but I think this is enough for an MVP.

![Screenshot 2026-03-27 at 11.10.53 AM.png](/attachments/3ac271a6-5d17-4063-9ac6-3e5bdef10ccf)

Co-authored-by: mplorentz <mplorentz@noreply.gitea.coracle.social>
Reviewed-on: #109
Co-authored-by: Matt Lorentz <mplorentz@noreply.coracle.social>
Co-committed-by: Matt Lorentz <mplorentz@noreply.coracle.social>
2026-03-27 19:02:56 +00:00
mplorentz 82245d895c Voice Room Membership Error (#106)
Before this we were showing "Failed to join voice room" if the relay rejected our request for a livekit token because we aren't a member of the room. Now it shows the error "Failed to join voice room: you must be a member."

Co-authored-by: mplorentz <mplorentz@noreply.gitea.coracle.social>
Reviewed-on: #106
Co-authored-by: Matt Lorentz <mplorentz@noreply.coracle.social>
Co-committed-by: Matt Lorentz <mplorentz@noreply.coracle.social>
2026-03-27 17:45:42 +00:00
Jon Staab 610b8dd171 Use secure storage for session data 2026-03-23 17:51:51 -07:00
Jon Staab f5b1e91378 Handle json parsing errors on file upload 2026-03-23 14:34:45 -07:00
Jon Staab 1de6d7a874 Set up default messaging relays 2026-03-23 14:21:04 -07:00
Jon Staab b716f3f792 Improve dm relay defaults and warnings 2026-03-23 12:53:24 -07:00
Jon Staab 75053bbbb1 Create health check framework 2026-03-23 11:17:45 -07:00
Jon Staab f9c7ed4936 Move relay action items to top of page 2026-03-19 12:41:23 -07:00
hodlbod 1f5be54cb1 Migrate Reports dialog to ActionItems dialog, add room join requests to queue 2026-03-19 15:40:34 +00:00
hodlbod 0761cdd28f Add android fallback for background push notifications (#102) 2026-03-19 15:32:32 +00:00
Jon Staab 7e2a0e9d5f Show notification badges regardless of favorite status 2026-03-17 15:11:02 -07:00
Jon Staab 7ae887561d Remove bad signers, fix some ui bugs 2026-03-17 15:05:46 -07:00
Jon Staab baa1d49b3a Tweak mobile nav 2026-03-17 15:03:40 -07:00
Jon Staab 58a6be911a Hide close button in dialog if in a noEscape modal 2026-03-17 14:55:40 -07:00
mplorentz 368f0b048b Expect pubkey in kind 39004 (#101)
This adjusts our implementation of the Livekit presence event to match the NIP (https://github.com/nostr-protocol/nips/pull/2238#issuecomment-4057645310). Specifically we now expect the user's Nostr pubkey in the `participant` tag instead of the livekit identity string.

I also fixed a bug I found where a malformed `participant` tag would crash the rendering of VoiceWidget, causing it to appear frozen.

There is a corresponding zooid PR [here](https://github.com/coracle-social/zooid/pull/11)

Co-authored-by: mplorentz <mplorentz@noreply.gitea.coracle.social>
Reviewed-on: #101
Co-authored-by: Matt Lorentz <mplorentz@noreply.coracle.social>
Co-committed-by: Matt Lorentz <mplorentz@noreply.coracle.social>
2026-03-17 19:38:10 +00:00
Jon Staab 10894e17a5 Fix phantom badges 2026-03-16 13:46:00 -07:00
Jon Staab ec8a7a40e2 Fix room icon 2026-03-16 13:42:01 -07:00
mplorentz ce30820108 feature/23-voice-room/poc (#93)
Add voice rooms

Co-authored-by: Matt Lorentz <mplorentz@noreply.coracle.social>
Co-committed-by: Matt Lorentz <mplorentz@noreply.coracle.social>
2026-03-16 20:38:05 +00:00
Jon Staab 147c756cc1 Update readme to point to .env.local 2026-03-16 13:36:06 -07:00
Jon Staab c7fb404404 Add -s flag to readme 2026-03-13 13:23:31 -07:00
Jon Staab 2546146ca8 Tweak back button, hide on desktop 2026-03-13 09:11:08 -07:00
Jon Staab ffa776fd42 Make mobile check on relay page reactive 2026-03-12 17:31:28 -07:00
Jon Staab a59ffb8758 Fix some icons, add privacy nav item, add close button to modal dialog, make settings menu nicer 2026-03-12 17:21:53 -07:00
Jon Staab 9e74c94871 Show navigation on space landing on mobile 2026-03-12 16:44:22 -07:00
Jon Staab 77294e7f1c Factor primary nav spaces into its own component, fix non-nip29 default page 2026-03-12 15:08:31 -07:00
Jon Staab 57f2f4a619 Use new space icon 2026-03-12 14:45:19 -07:00
Jon Staab 1df2284ea3 Return more details about notification registration failure 2026-03-12 14:07:52 -07:00
Jon Staab 189af077e7 Fix file uploads on android 2026-03-12 13:51:05 -07:00
Jon Staab 10e4d83bce Hide add member button for non-members 2026-03-12 12:35:08 -07:00
Jon Staab 5d6661f964 Speed up boot, prune stores 2026-03-12 11:33:04 -07:00
Jon Staab e6e11bb8f2 Massive indexeddb optimization 2026-03-12 11:01:15 -07:00
Jon Staab 0e65e834da Bump welshman 2026-03-12 08:20:15 -07:00
Jon Staab 19f532c12e Allow nested modals 2026-03-11 16:29:24 -07:00
Jon Staab bfc997ba37 Tweak icon picker modal 2026-03-11 16:15:37 -07:00
Jon Staab 99966a976e Overhaul relay settings page 2026-03-11 15:58:05 -07:00
Jon Staab cd54bc2880 Add up/edit to chats 2026-03-10 15:46:59 -07:00
Jon Staab ffdd689331 Add another pomade signer 2026-03-10 11:09:59 -07:00
Jon Staab af41d81981 Add pomade signers 2026-03-10 10:15:53 -07:00
Jon Staab 10d28ed364 Update zapstore.yaml
Docker / build-and-push-image (push) Successful in 15m7s
2026-03-09 21:12:51 -07:00
Jon Staab b02f4bd53a Update version 2026-03-09 21:12:51 -07:00
Jon Staab 7ce8e3dbe6 Fix classified images 2026-03-09 21:12:51 -07:00
Jon Staab 2446d5cdb8 Add StringMultiInput for OTPs 2026-03-09 21:12:51 -07:00
Jon Staab d015018a16 Fix up edit 2026-03-09 21:12:51 -07:00
Jon Staab 6231c75e34 Handle prompt-with-rationale 2026-03-09 21:12:51 -07:00
Jon Staab 2f3bc6cc6f Handle profile update errors 2026-03-09 21:12:50 -07:00
Jon Staab 16c6015919 Move from .env to .env.local 2026-03-09 21:12:50 -07:00
Jon Staab e6b291cc68 Tweak some error messages 2026-03-09 21:12:37 -07:00
Jon Staab ae523c1ca6 Refactor pomade, add password reset flow 2026-03-09 21:12:37 -07:00
Jon Staab 7c86c1477f Add LogInSelect step for disambiguating pomade sessions 2026-03-09 21:12:37 -07:00
Jon Staab 71f162f20d Update pomade implementation 2026-03-09 21:12:37 -07:00
mplorentz eeacaca725 Fix a docker rebuild issue (#88)
The Docker build wasn't making use of docker's cache because the .git directory was being copied into the build context. This means that even if the app did not change, if anything in git changed then docker would rebuild the entire app.

This excludes the .git folder from the docker build, instead relying on the user to pass in the build hash at build time. Which is annoying but I don't think there's a better way around it.

This was annoying me because I am deploying a self-hosted version of flotilla from a git branch via ansible and it was rebuilding flotilla every time.

Co-authored-by: mplorentz <mplorentz@noreply.gitea.coracle.social>
Reviewed-on: #88
Co-authored-by: Matt Lorentz <mplorentz@noreply.coracle.social>
Co-committed-by: Matt Lorentz <mplorentz@noreply.coracle.social>
2026-03-09 21:12:35 -07:00
Jon Staab af52ee25eb Bring back some notification badges 2026-03-09 21:12:10 -07:00
Jon Staab eef32ca11e Make sync logic more robust 2026-03-09 21:12:10 -07:00
Jon Staab 1ae821bff8 Bump welshman 2026-03-09 21:12:10 -07:00
Jon Staab 65483a6ef0 Support unban/unallow 2026-03-09 21:12:10 -07:00
Jon Staab 606a9343d9 Fix WalletPay 2026-03-09 21:12:10 -07:00
Jon Staab 7dfa6538be Bump welshman 2026-03-09 21:12:10 -07:00
Jon Staab 476d010ebe Blobify images so users can open them easier 2026-03-09 21:12:10 -07:00
Jon Staab 96d2efebc8 Add manual invoice payment 2026-03-09 21:12:10 -07:00
Jon Staab f60f5af424 Update link_deps 2026-03-09 21:12:10 -07:00
Jon Staab 3da0334083 Fix enter selecting an option when there is no term. Closes #84 2026-03-09 21:12:10 -07:00
triesap c970038943 Bootstrap Tauri desktop shell for evaluation (#66)
Adds a minimal Tauri desktop bootstrap. Run with: pnpm run tauri:dev

Reviewed-on: #66
Co-authored-by: triesap <tyson@radroots.org>
Co-committed-by: triesap <tyson@radroots.org>
2026-03-09 21:12:10 -07:00
triesap 4000477bdb Classifieds tags (#18) (#65)
Closes #18

Reviewed-on: #65
Co-authored-by: triesap <tyson@radroots.org>
Co-committed-by: triesap <tyson@radroots.org>
2026-03-09 21:12:10 -07:00
triesap ba11d53922 Show wallet status when wallet is unreachable 2026-03-09 21:12:10 -07:00
Jon Staab beef606024 Remove capacitor plugin from overrides 2026-03-09 21:12:10 -07:00
Jon Staab 2adf64da55 Bump welshman and pomade 2026-03-09 21:12:10 -07:00
Jon Staab fd3fb8573c Update nostr signer capacitor plugin 2026-03-09 21:12:09 -07:00
Jon Staab e0d94d9794 Fix safe area inset for modal footer 2026-03-09 21:12:09 -07:00
Jon Staab 7d049150a0 Bump nip55 signer 2026-03-09 21:12:09 -07:00
Jon Staab 527ef59adc Update pomade version 2026-03-09 21:12:09 -07:00
Jon Staab b39775daef Fix svgs with 302 redirects on safari 2026-03-09 21:12:09 -07:00
Jon Staab 4bdb21560a Fix mask-repeat property 2026-03-09 21:12:09 -07:00
Jon Staab 797a9c32aa Refine space join dialogs and discover page 2026-03-09 21:12:09 -07:00
mplorentz bc864b29f8 Reopen the last DM that was open when navigating back to chat (#81)
#60

Co-authored-by: mplorentz <mplorentz@users.noreply.github.com>
Reviewed-on: #81
Co-authored-by: Matt Lorentz <mplorentz@noreply.coracle.social>
Co-committed-by: Matt Lorentz <mplorentz@noreply.coracle.social>
2026-03-09 21:12:09 -07:00
Jon Staab 482121db5c Add content-visibility class 2026-03-09 21:12:09 -07:00
Jon Staab 0fa26c8d0a Get rid of ChatEnable, automatically enable unwrapping when the user first visits the dms page. Closes #72 2026-03-09 21:12:09 -07:00
Jon Staab f5c768d6a7 Enable auth for relays we're publishing to 2026-03-09 21:12:09 -07:00
triesap c43544734a Drag and drop space icons (#17) (#78)
Closes #17

Co-authored-by: Jon Staab <shtaab@gmail.com>
Reviewed-on: #78
Co-authored-by: triesap <tyson@radroots.org>
Co-committed-by: triesap <tyson@radroots.org>
2026-03-09 21:12:09 -07:00
Jon Staab 86d99916f7 re-order some menu items 2026-03-09 21:12:09 -07:00
Jon Staab 135dbc8789 Fix iOS zoom bug 2026-03-09 21:12:09 -07:00
Jon Staab fc14de9b0f Reset to old home page 2026-03-09 21:12:09 -07:00
Jon Staab c77197d959 Continue working on feed page 2026-03-09 21:12:09 -07:00
Jon Staab 56dddbdd86 Add better muting, add EventReducer 2026-03-09 21:12:09 -07:00
mplorentz cbafcf6939 Add back button to settings menu 2026-03-09 21:12:09 -07:00
Jon Staab 4b156ee699 Work on feed page 2026-03-09 21:12:09 -07:00
Jon Staab a4e883b09a Prevent error loop on images 2026-03-09 21:12:09 -07:00
triesap b114a724e2 Page titles (#16) (#62)
Closes #16

Reviewed-on: #62
Co-authored-by: triesap <tyson@radroots.org>
Co-committed-by: triesap <tyson@radroots.org>
2026-03-09 21:12:09 -07:00
Jon Staab 621c0d839c tweak how at works 2026-03-09 21:12:09 -07:00
Jon Staab 021c1fc7c4 Fix scroll to event behavior 2026-03-09 21:12:08 -07:00
Jon Staab bda91080ab Pin scroll position to at'd event until user scrolls 2026-03-09 21:12:08 -07:00
Jon Staab a9828be25c Simplify goToEvent 2026-03-09 21:12:08 -07:00
Jon Staab dde9dbfbfe Add forward scrolling to makeMakeFeed 2026-03-09 21:12:08 -07:00
Jon Staab ca7d126a3c Make createScroller honor reverse param 2026-03-09 21:12:08 -07:00
Jon Staab 7f6450375b Fix duplicate ids in chat 2026-03-09 21:12:08 -07:00
Jon Staab c9954db3fe Use compressorjs-next 2026-03-09 21:12:08 -07:00
Jon Staab 3d268f1f9d Refactor SpaceSearch into its own component 2026-03-09 21:12:08 -07:00
Ben 66a7a2a7af Space search 2026-03-09 21:12:08 -07:00
Jon Staab 7823e1d803 Fix editing messages with html tags 2026-03-09 21:12:08 -07:00
Jon Staab d5e91ce874 Fix DM media detection 2026-03-09 21:12:08 -07:00
Jon Staab 6f32c1932f Make hover target for menu button more reasonable 2026-03-09 21:12:08 -07:00
Jon Staab cb06c4e954 Watch tracker in feed utils 2026-03-09 21:12:08 -07:00
Jon Staab 9188c0a8bc Revert makeFeed changes 2026-03-09 21:12:08 -07:00
Jon Staab 30653fe344 Clean up report item design, bad/restore user actions, space description input, add feed to home page 2026-03-09 21:12:07 -07:00
Jon Staab 5bb55c453f Tweak wallet page 2026-03-09 21:12:07 -07:00
Jon Staab 3024e08ca5 Fix makeFeed (maybe) 2026-03-09 21:12:07 -07:00
Jon Staab aaf1f25167 Tweak room detail 2026-03-09 21:12:07 -07:00
Jon Staab aabbb758a4 Fix scroll to bottom button safe insets 2026-03-09 21:12:07 -07:00
Jon Staab d824f928b5 Disable wallet on ios 2026-03-09 21:12:07 -07:00
Jon Staab 445ed27eb8 Add rewrite to dockerfile
Docker / build-and-push-image (push) Successful in 14m14s
2026-02-17 12:01:12 -08:00
Jon Staab 21f3970ca8 Use explicit image name in workflow file
Docker / build-and-push-image (push) Has been cancelled
2026-02-17 11:48:52 -08:00
Jon Staab 919fe29ffb Update docker image creation for gitea ci
Docker / build-and-push-image (push) Failing after 20m22s
2026-02-17 10:45:39 -08:00
Jon Staab 3b2870a318 Bump version
Docker / build-and-push-image (push) Has been cancelled
2026-02-10 17:14:02 -08:00
Jon Staab 1076e8531c Slightly tweak notifications function 2026-02-10 17:04:21 -08:00
Jon Staab 72f2effda4 Clean up modals 2026-02-10 11:39:29 -08:00
Jon Staab 7566f56858 Fix tippy placement for icon picker 2026-02-09 17:40:10 -08:00
Jon Staab c1f9c9e25e Bump welshman 2026-02-09 17:29:30 -08:00
Jon Staab 380a52efb3 Use space url as relay hint 2026-02-09 17:24:55 -08:00
Jon Staab 028c3ba92b Fix badge showing on current page 2026-02-09 17:11:03 -08:00
Jon Staab f80aba33f1 Optimistically load messaging relays 2026-02-09 16:57:44 -08:00
Jon Staab bb15c9e2d0 Fix last activity reactivity 2026-02-09 13:21:38 -08:00
Jon Staab 518c80bb1d Fix indexeddb failure 2026-02-09 11:59:58 -08:00
Jon Staab 0067d049e6 Tweak signer error 2026-02-09 11:44:50 -08:00
Jon Staab bf60dd24aa Handle sai in modals on small screens 2026-02-09 11:44:50 -08:00
Jon Staab 38d9cc4892 Add modal body to some menus 2026-02-09 11:44:50 -08:00
hodlbod c4f2f55617 Simplify notification badges, improve performance (#57)
Co-authored-by: Jon Staab <shtaab@gmail.com>
2026-02-09 11:44:32 -08:00
Jon Staab 8f73fb85e9 Show space url in page top bar 2026-02-09 08:42:30 -08:00
Jon Staab 3bd126c11d Fix a modal 2026-02-06 16:27:57 -08:00
Jon Staab 7e7aba06a6 Fix safe area insets 2026-02-06 14:57:36 -08:00
Jon Staab 2bf00f7ddc Tweak room/space icon buttons 2026-02-06 14:57:35 -08:00
Jon Staab 24b88e4ac0 Fix calendar detail 2026-02-06 14:57:35 -08:00
Jon Staab 3df3130395 remove pomade from links 2026-02-06 14:57:35 -08:00
Jon Staab c0c388d1b9 Tweak syncing so it works better for picky relays 2026-02-06 14:57:35 -08:00
Jon Staab 9f27cc61da Ignore another invite code error 2026-02-06 14:57:35 -08:00
Jon Staab 8fa1987ec0 Slight tweaks to wallet receive 2026-02-05 13:23:56 -08:00
Jon Staab 39eae42b05 Make space/room images a little bigger 2026-02-05 13:20:18 -08:00
Tyson Lupul 4dfbb437f9 Wallet receive flow (#15) (#52)
* Pin sharp via pnpm override, add wallet receive

* Revert toast success styling

* Route receive through wallet connect

* Simplify receive invoice validation

* Polish receive modal layout

* Clarify NWC client config

* Adjust wallet action layout on mobile
2026-02-05 20:51:59 +00:00
Jon Staab f132d22308 Revert safari fix (merged into nostr-editor) 2026-02-04 13:18:18 -08:00
Jon Staab b7dd2ff8b4 Bump welshman 2026-02-04 13:16:00 -08:00
Jon Staab b6b78591bc Update push impl 2026-02-04 10:37:50 -08:00
Jon Staab ec54a0dbce Use item components on recent page 2026-02-04 09:07:26 -08:00
Jon Staab 8793912b65 Prompt to add space members when adding room members 2026-02-03 17:38:22 -08:00
Jon Staab 70c430ddc2 Add classified status 2026-02-03 17:09:30 -08:00
Jon Staab 815dbba497 Use address for page param for replaceable events 2026-02-03 16:35:32 -08:00
Jon Staab dc5bac67aa Add image uploads to classifieds 2026-02-03 14:18:58 -08:00
Jon Staab 5427fd7860 Add a currency input 2026-02-03 13:25:24 -08:00
Jon Staab 119c09d730 Add classified listings 2026-02-03 12:43:36 -08:00
Jon Staab 1da6833c71 Rework recent activity page 2026-02-03 09:51:33 -08:00
Jon Staab 4b8cf53731 Rework recent activity page 2026-02-02 15:36:50 -08:00
Jon Staab d646ddd91d Fix edit 2026-02-02 14:33:45 -08:00
Jon Staab 764719afde Fix some notification related bugs 2026-02-02 14:29:12 -08:00
Jon Staab 75ec7688b1 Fix image uploads on ios 2026-02-02 14:06:36 -08:00
Jon Staab 7fc508603f Bring back service worker 2026-02-02 10:35:05 -08:00
Jon Staab fb2d78fd57 Rework modal header structure 2026-02-02 10:09:14 -08:00
Jon Staab 4480132c74 Add sticky submit buttons to settings pages 2026-02-02 09:51:36 -08:00
Jon Staab 38c0a9d403 Re work modal scrolling 2026-01-30 15:36:20 -08:00
Jon Staab 4169db33e6 Rework alert settings and UI 2026-01-30 09:13:50 -08:00
Jon Staab ee48072137 Add AGENTS.md 2026-01-29 15:09:26 -08:00
Jon Staab a3c1a5c731 Prevent icon picker from going off screen 2026-01-29 13:52:36 -08:00
Jon Staab e74f922e8d Fix tippy falling off the page 2026-01-29 13:52:36 -08:00
Jon Staab 16cd90f7b7 Refine discover page a bit to avoid slowness 2026-01-29 13:52:36 -08:00
Jon Staab e2ba10d224 Fix has alerts store 2026-01-29 13:52:36 -08:00
Jon Staab 459e9359db Disable macos build 2026-01-29 13:52:36 -08:00
Jon Staab d2a044f958 Small ui fixes 2026-01-29 13:52:36 -08:00
Jon Staab 2fbcd644d0 Tag event author when tagging parent event 2026-01-29 13:52:36 -08:00
Jon Staab cf8e736f46 Handle encrypted notifications 2026-01-29 13:52:04 -08:00
Jon Staab d4378731ae Fix a few bugs with push notifications 2026-01-28 14:08:15 -08:00
Jon Staab 000344a942 Fixing bugs with push notifications 2026-01-28 13:36:19 -08:00
Jon Staab bf6abd301c refactor notification syncing 2026-01-27 17:15:22 -08:00
Jon Staab 143a1dd39b Update notification subscriptions reactively 2026-01-27 13:38:24 -08:00
Jon Staab 9b3a8258ce Disable alerts on logout 2026-01-26 10:08:43 -08:00
Jon Staab 646b8f8736 Rework subscription storage 2026-01-23 16:51:02 -08:00
Jon Staab 2528e4acad Clean up and fix push notifications implementation 2026-01-23 15:35:54 -08:00
Jon Staab 286d939097 Moar upgrades 2026-01-23 10:53:50 -08:00
Jon Staab ca3d661830 Generally just refactor alerts, upgrade some deps 2026-01-23 10:05:47 -08:00
Jon Staab 63fee653e8 Add muted rooms, rework alert settings 2026-01-22 12:49:09 -08:00
Jon Staab 9da2473976 Add apns/fcm push notifications with new architecture 2026-01-21 16:20:48 -08:00
Jon Staab 6d1eeacc49 Add new alerts 2026-01-20 13:42:58 -08:00
Jon Staab f85748fef9 Remove old alerts 2026-01-19 16:33:49 -08:00
Jon Staab 9f34b33b7e Remove sourcemaps command 2026-01-19 10:40:56 -08:00
Jon Staab 1510f39a8a Bump ios version 2026-01-19 10:07:44 -08:00
Jon Staab bbbe011482 Publish default relay selections on signup 2026-01-16 16:11:45 -08:00
Jon Staab 82ab7a043f Remove glitchtip integration 2026-01-16 15:19:52 -08:00
Jon Staab 798253a50e Bump welshman 2026-01-16 15:07:55 -08:00
Jon Staab 52432ca068 Add sign in with private key 2026-01-16 14:25:44 -08:00
Jon Staab b3f1d8464b Add authentication policy setting 2026-01-16 13:49:35 -08:00
Jon Staab 87bb62b359 Add support for blocked relays 2026-01-16 13:10:48 -08:00
Jon Staab 3f914d02cc Fix signer disconnection flash, nav icon sizes 2026-01-16 11:33:03 -08:00
Jon Staab d1db77d0f5 Bump version 2026-01-16 11:01:24 -08:00
Jon Staab 6aa297c1a4 Rework onboarding flow, add recovery 2026-01-16 11:01:07 -08:00
Jon Staab f3647e9bc1 Use simple OTPs 2026-01-16 11:01:07 -08:00
Jon Staab 5b43c62f2d Remove pomade signers 2026-01-16 11:01:07 -08:00
Jon Staab 23ffb15a8d Fix incorrect secret being downloaded 2026-01-16 11:01:07 -08:00
Jon Staab adb2ce4846 Split key recovery components, bump deps 2026-01-16 11:01:06 -08:00
Jon Staab cdee6ca743 Add pomade key recovery 2026-01-16 11:00:46 -08:00
Jon Staab fe30aa4af2 Fix ContentLinkInline 2026-01-16 11:00:45 -08:00
Jon Staab 9943728eab Add pomade session list 2026-01-16 11:00:00 -08:00
Jon Staab 8ae7cf05cc Fix profile publishing on email sign up 2026-01-16 11:00:00 -08:00
Jon Staab a7c944e8ef Tweak breakpoint for field inline 2026-01-16 11:00:00 -08:00
Jon Staab 102339d7e8 Add link_peers script 2026-01-16 10:59:59 -08:00
Jon Staab 9a0ad0c663 Improve space join flow 2026-01-16 10:59:54 -08:00
Jon Staab f86afc08fa Normalize relay URLs 2026-01-16 10:59:46 -08:00
Jon Staab cd1b328b1b Add pomade signing 2026-01-16 10:59:45 -08:00
Jon Staab 48f2bb1c75 Bump gradle 2026-01-16 10:59:30 -08:00
Jon Staab d416fe913e Fix memory leak, notification badge not showing 2026-01-16 10:59:29 -08:00
Jon Staab 7f8744725c Improve signer status 2026-01-16 10:59:25 -08:00
Jon Staab e5d1b82a9d Fix chat list responsiveness 2026-01-16 10:59:22 -08:00
Jon Staab 619cf2e134 Update default relays 2026-01-16 10:59:16 -08:00
Jon Staab 28b522f015 Report pending signer to user 2026-01-16 10:59:10 -08:00
Jon Staab 39233f261e Force reload relay more simply 2026-01-16 10:59:05 -08:00
Jon Staab 00f0127caf Tweak room edit form 2026-01-16 10:59:03 -08:00
Jon Staab f69b575381 Fix some duplicates in eaches 2026-01-16 10:58:57 -08:00
Jon Staab 986973a605 Accept hex pubkeys/npubs/nprofiles in ProfileMultiSelect 2026-01-16 10:58:55 -08:00
Jon Staab 0d6b4591f1 Hide tooltips on mobile, sort comments ascending, make video embeds rounded 2026-01-16 10:58:40 -08:00
Jon Staab 2c62749d9b Attempt to fix new messages button 2026-01-16 10:56:18 -08:00
Jon Staab 4be4288ef0 Fix phantom notifications on mobile 2025-12-11 10:27:10 -08:00
Jon Staab c7eec167cf Fix scroll down z index 2025-12-08 09:27:38 -08:00
Jon Staab 7bae956ffa Release 1.6.2 2025-12-08 09:22:49 -08:00
Jon Staab a2f59a5b1b Fix some modal bugs 2025-12-08 09:19:41 -08:00
Jon Staab df56af9b0e Bump version 2025-12-05 09:51:15 -08:00
Jon Staab 83f7f9584f Fix duplicate rooms 2025-12-04 17:06:50 -08:00
Jon Staab a2d440e54f Fix dialog z index 2025-12-04 16:01:39 -08:00
Jon Staab 4132e8449b Fix recent missing events in feeds 2025-12-04 15:56:05 -08:00
Jon Staab ee444416e4 Fall back to file name as hash for images 2025-12-04 14:37:59 -08:00
Jon Staab 10c12c3c48 Improve time based chat partitioning 2025-12-04 14:29:12 -08:00
Jon Staab db3775ae99 Fix timezone parsing in AlertAdd 2025-12-04 11:20:54 -08:00
Jon Staab 393acce884 Fix removing non-normalized urls 2025-12-02 17:27:14 -08:00
Jon Staab 68fe663730 Fix chat content bottom offset when keyboard is open 2025-12-02 17:20:10 -08:00
Jon Staab f65a4b0db0 Handle relay urls in content and link within the app 2025-12-02 17:09:56 -08:00
Jon Staab cdfb502e6e Fix skinny profile circles 2025-12-02 13:49:04 -08:00
Jon Staab 1a2c83e49b Bump version 2025-12-02 13:38:03 -08:00
Jon Staab e6c7a675a9 Bump welshman 2025-12-02 13:24:43 -08:00
Jon Staab 69c04f29f4 Tweak zap button 2025-12-02 09:31:38 -08:00
Jon Staab 04c6f9b4fe Add date to chats 2025-12-01 11:09:26 -08:00
Jon Staab 86ec12a9db Tweak some mobile menu components 2025-12-01 11:04:11 -08:00
Jon Staab 72b3111c64 Refine sync 2025-12-01 10:56:37 -08:00
Jon Staab 6709c91779 Fix discover social proof 2025-12-01 10:26:43 -08:00
Jon Staab bb6e7495f5 Add editor props from nostr-editor 2025-12-01 08:45:35 -08:00
Jon Staab df17929681 Fix new messages indicator 2025-11-25 17:06:21 -08:00
Jon Staab e083719ceb Hide nav when keyboard is open 2025-11-25 15:43:21 -08:00
Jon Staab bfdc69f18c Fix chats 2025-11-25 15:05:45 -08:00
Jon Staab e7ae20afb7 Fix content type nav items 2025-11-25 14:13:28 -08:00
Jon Staab 229d92055f Debounce search 2025-11-25 11:55:32 -08:00
Jon Staab 64c77cfd13 Migrate to new welshman stores 2025-11-21 12:40:59 -08:00
Jon Staab 3a63894562 Switch wording to messaging from inbox 2025-11-20 15:12:16 -08:00
Jon Staab 1d272f8b37 Tweak nav icon size 2025-11-14 15:02:23 -08:00
Jon Staab bac433b640 Re-work storage adapter a bit 2025-11-14 14:59:27 -08:00
Jon Staab 62f573eac0 Merge report detail components 2025-11-14 11:36:51 -08:00
Jon Staab b3ea62c53c Remove landlubber link 2025-11-13 17:01:23 -08:00
Jon Staab b0731503a8 Fix indexeddb deletes 2025-11-13 16:39:44 -08:00
Jon Staab 2421c02c24 Add room membership management 2025-11-13 15:25:18 -08:00
Jon Staab 25e868118d Slight optimization 2025-11-13 14:40:02 -08:00
Jon Staab 2880044e0e Add event admin deletion 2025-11-13 14:25:59 -08:00
Jon Staab 5300404b46 Add option to ban users from profile detail dialog 2025-11-13 13:44:52 -08:00
Jon Staab d949d58076 Add space membership management 2025-11-13 13:25:34 -08:00
Jon Staab 997b223e95 Rename space menu components 2025-11-13 10:36:28 -08:00
Jon Staab ba52a97e26 Tweak relay icon size in nav 2025-11-13 10:34:02 -08:00
Jon Staab cc4c7b5fe9 Fix image modal, only show + room if the user is allowed 2025-11-13 10:32:37 -08:00
Jon Staab 8e2ebd11fc remove some alts 2025-11-13 08:59:32 -08:00
Jon Staab 9cae4da9f4 Add lightning invoice payments 2025-11-12 16:24:58 -08:00
Jon Staab c05d7e99e2 remove old icon picker 2025-11-12 14:56:14 -08:00
Jon Staab 2390599e8f Fix relay updating and relay icons 2025-11-11 17:48:24 -08:00
Jon Staab 1a4d45fa9c Upload svgs for room icon 2025-11-11 17:34:15 -08:00
Jon Staab 57447e5bf4 Bump version 2025-11-11 14:09:05 -08:00
Jon Staab 8e411daaef Refactor avatar components, add space edit form 2025-11-11 13:50:45 -08:00
Jon Staab 183aebf841 Improve room syncing 2025-11-10 16:19:50 -08:00
Jon Staab e3e500ccc2 Return better blossom errors 2025-11-10 16:02:02 -08:00
Jon Staab e7a2535ece Fix access restricted after successful invite code 2025-11-10 15:24:11 -08:00
Jon Staab 761e369313 Add room detail, assume admins are members 2025-11-10 14:59:15 -08:00
Jon Staab 5248275d73 Fix nav index 2025-11-10 13:20:42 -08:00
Jon Staab cb033279dd Fix link 2025-11-06 11:25:07 -08:00
Jon Staab 41d50d8c28 Add room policy indicator 2025-11-05 16:59:17 -08:00
Jon Staab a52c2b4c3c Lighten up shadows 2025-11-05 15:32:55 -08:00
Jon Staab b5917cb184 Show loading on spaces menu 2025-11-05 15:24:46 -08:00
Jon Staab 57348472f8 Always join spaces when visiting them 2025-11-05 15:09:23 -08:00
Jon Staab 4b6223dc00 Update changelog 2025-11-05 09:46:05 -08:00
Jon Staab 5525e45a15 Bump version, upgrade welshman 2025-11-05 09:42:27 -08:00
Jon Staab 80a2ae60b0 Bump version 2025-11-04 17:28:27 -08:00
Jon Staab d7e95f5d2f Fix chat url 2025-11-04 17:25:50 -08:00
Jon Staab ca4e5ae5ee Add shadow to thread items etc, bump welshman, update changelog, update version 2025-11-04 17:14:33 -08:00
Jon Staab b673658c0c Handle escape in chat 2025-11-04 16:59:17 -08:00
Jon Staab 5c5c130700 Add landlubber link if user is admin 2025-11-04 16:55:26 -08:00
Jon Staab 2d89ca6c0e Support invite links on discover page 2025-11-04 16:39:34 -08:00
Jon Staab 806a7c2609 Persist alert kinds again 2025-11-04 16:25:21 -08:00
Jon Staab 501ce8067d Detect nip29 properly before choosing smart path, more robust auth error checking 2025-11-04 16:14:32 -08:00
Jon Staab 6429f82829 Improve claim/access detection 2025-11-04 15:36:20 -08:00
Jon Staab fe626218ea Ignore aborted signatures when checking auth 2025-11-04 09:34:07 -08:00
Jon Staab b62b1bc063 Don't source local .env file on build 2025-11-04 09:18:26 -08:00
Jon Staab d980f36246 Use request instead of load to avoid timeouts 2025-11-04 09:05:17 -08:00
Jon Staab b469addd29 Remove withGetter 2025-11-03 14:52:12 -08:00
Jon Staab 6923c2a8b7 Tweak modal, reduce storage on mobile 2025-11-03 14:43:27 -08:00
Jon Staab 1d3f32fb99 Only return error from attemptRelayAccess if there is a claim sent 2025-11-03 12:08:50 -08:00
Jon Staab 42a550788a Fix some alerts stuff 2025-11-03 11:10:16 -08:00
Jon Staab b1c68972c9 Streamline deriveRoom 2025-10-31 16:19:22 -07:00
Jon Staab 3978e32d5f Tweak access terminology, relay access attempts 2025-10-31 16:00:14 -07:00
Jon Staab ba2b5d182e Fix alerts 2025-10-31 14:51:59 -07:00
Jon Staab bef04fa899 Add holis to hosting suggestions 2025-10-31 14:02:52 -07:00
Jon Staab 4f8609421c Fix membership status 2025-10-31 12:10:16 -07:00
Jon Staab 07660c9d44 Re-work rooms derivation 2025-10-30 15:52:24 -07:00
Jon Staab a324dad2ba Rename channel to room 2025-10-30 15:36:14 -07:00
Jon Staab dbaa0f5d49 Rename room variables to h 2025-10-30 15:33:34 -07:00
Jon Staab 478721d349 Add room editing 2025-10-30 15:22:31 -07:00
Jon Staab a669a23dbc Tweak reaction buttons 2025-10-30 12:53:21 -07:00
Jon Staab cfeb6478cc Fix flapping subscription 2025-10-30 12:06:53 -07:00
Jon Staab 64539c49c1 Fix link, spinner animation 2025-10-30 07:20:09 -07:00
Jon Staab 0399ae37ec Move space create to its own page 2025-10-29 12:52:26 -07:00
Jon Staab 173a411a36 Update space create dialog 2025-10-29 11:18:27 -07:00
Jon Staab 62013a2ea2 Tweak mobile space menu 2025-10-28 16:50:15 -07:00
Jon Staab c82cf4a4c2 Update platform url 2025-10-28 16:08:48 -07:00
Jon Staab df42085be6 Sync messages at the space level 2025-10-28 15:46:25 -07:00
Jon Staab b09d3065ae Fix app url on capacitor deployments 2025-10-28 15:40:28 -07:00
Jon Staab c050f5a9e3 Update changelog 2025-10-28 15:37:36 -07:00
Jon Staab 78e6c0eca0 Bump version 2025-10-28 15:35:39 -07:00
Jon Staab da4da45348 Load rooms correctly 2025-10-28 14:53:44 -07:00
Jon Staab dc2af86db8 Bump welshman 2025-10-28 13:26:02 -07:00
Jon Staab 7502004aba Improve syncing 2025-10-28 11:29:59 -07:00
Jon Staab 2e8678e4c6 Bump welshman 2025-10-27 15:08:34 -07:00
Jon Staab 97569016fc Bump version 2025-10-27 14:19:06 -07:00
Jon Staab fe72798592 Send leave request 2025-10-27 14:13:17 -07:00
Jon Staab 4583c4e028 fix zapper loading 2025-10-27 13:36:29 -07:00
Jon Staab 0b98197a86 Add room deletion 2025-10-24 13:36:59 -07:00
Jon Staab 0e94a9c33f Use imperative svelte api for modals 2025-10-24 10:27:15 -07:00
Jon Staab 3dff1fcb4d Switch to new relays store 2025-10-24 09:38:57 -07:00
Jon Staab e163286dd4 Re-render suggestions on search update; prioritize space members in search 2025-10-24 09:09:59 -07:00
Jon Staab a99e12f12e Bump welshman 2025-10-24 06:47:20 -07:00
Matthew Remmel c3dd997e57 Add icon picker to room create component 2025-10-24 06:38:03 -07:00
Matthew Remmel a730384baf Add relay members list and room join/leave events 2025-10-24 05:03:22 -07:00
Jon Staab 43cf91e877 Remove connection toast now that we have a cta surfaced 2025-10-22 08:35:42 -07:00
Jon Staab 75bee027e1 Remove shards entirely, fix setup in layout 2025-10-21 10:29:29 -07:00
Jon Staab 5cbf69a8bd Push shards into storage lib 2025-10-21 09:26:06 -07:00
Jon Staab ecbb3086d8 Handle hot module unloading in layout 2025-10-21 08:27:30 -07:00
Jon Staab 7476767aa7 Add space status indicator #245 2025-10-20 17:05:22 -07:00
Jon Staab e5b8987a9d Move nav item 2025-10-20 16:06:00 -07:00
Jon Staab 6ca74c21bf Update to new version of welshman, including new thunks and wrap manager 2025-10-20 15:42:41 -07:00
Jon Staab e0099141aa Refactor synchronization logic 2025-10-17 12:23:03 -05:00
Jon Staab d0491ed202 Re-work space navigation #223 2025-10-17 12:23:03 -05:00
Jon Staab cbc2137ced Show all messages in non-nip29 chat 2025-10-17 12:23:03 -05:00
Jon Staab f9ac13ba11 Re-work space navigation #223 2025-10-17 12:21:22 -05:00
Jon Staab b3533c285f Show all messages in non-nip29 chat 2025-10-17 09:13:54 -07:00
Matthew Remmel a636ae6592 Simplify room create permission derive 2025-10-17 09:13:54 -07:00
Matthew Remmel 69e3ee0aff Move create room permission check to menu space 2025-10-17 09:13:54 -07:00
Matthew Remmel a39a87ba6d Disable create room button if no permission 2025-10-17 09:13:54 -07:00
Matthew Remmel 5b22d6ac01 Allow editing previous messages in channel chat 2025-10-17 11:13:09 -05:00
Jon Staab 7334cd26f8 Bump version 2025-10-13 15:17:46 -07:00
Jon Staab 44555215cf Track shards separately, upgrade deps 2025-10-13 13:41:27 -07:00
Jon Staab 0cc25913c0 Optimize event storage 2025-10-13 12:46:56 -07:00
Jon Staab 004b30b737 Update caniuse 2025-10-13 11:48:22 -07:00
Jon Staab 632f330b4c Re-work storage to optimize file access 2025-10-06 17:01:25 -07:00
Jon Staab 666433912f Only show send toast in chat if send_delay is set 2025-10-06 11:27:07 -07:00
Jon Staab db98ce8db7 Bump welshman 2025-10-06 11:26:27 -07:00
Jon Staab 71dcfae5ff Add heading, update changelog, bump version 2025-10-02 12:43:19 -07:00
Jon Staab 04155f5b23 Bump welshman 2025-10-01 17:03:25 -07:00
Jon Staab b4058389ec Avoid decrypt errors 2025-10-01 10:06:21 -07:00
Jon Staab 483fa81b74 Fix some storage bugs 2025-09-30 17:04:52 -07:00
Jon Staab a8d1c4bbbc Refactor storage 2025-09-30 16:28:12 -07:00
Matthew Remmel 0a8c2faa74 Add filestorage adapters 2025-09-30 10:52:24 -07:00
Jon Staab dd3231e70f Bring back blossom server auth, fix duplicate direct messages 2025-09-29 14:25:07 -07:00
Jon Staab 7ff9c00032 Force url extension for encrypted uploads 2025-09-29 14:25:07 -07:00
Matthew Remmel 9ed483abf7 Ignore exception from if failing to set badge 2025-09-29 10:32:13 -07:00
Matthew Remmel b9aeaf29a4 Disable notification sound when tab is focused 2025-09-29 10:32:13 -07:00
Matthew Remmel 65e3f81f36 Remove comments and test lines 2025-09-29 10:32:13 -07:00
Matthew Remmel c6641dba31 Move notification sound and badge settings to settings store 2025-09-29 10:32:13 -07:00
Matthew Remmel e48d1e0e59 Fix async bug and add sound component for notification sound 2025-09-29 10:32:13 -07:00
Matthew Remmel d1e5aee84e Add naive badge count implementation 2025-09-29 10:32:13 -07:00
Matthew Remmel 5cb22d0bed Add checkboxes for badge/sound settings 2025-09-29 10:32:13 -07:00
Matthew Remmel d1c6f53d7c Add royalty-free sound effect for new notification 2025-09-29 10:32:13 -07:00
Matthew Remmel 6e238f98c0 Auto-add receiving address on wallet setup 2025-09-29 10:25:02 -07:00
Jon Staab 290274d6c8 Tweak light theme, remove conditional button classes 2025-09-25 10:52:32 -07:00
Jon Staab e1de0239c9 Remove css that was breaking tooltips 2025-09-25 10:43:55 -07:00
Jon Staab bec77d59e8 Add theme toggle on mobile, change button color for quick links 2025-09-25 10:37:53 -07:00
Jon Staab 84f8794d7c Make link previews less aggressive 2025-09-25 10:12:58 -07:00
Jon Staab 4cddf41bf3 Set initial delay to 0 2025-09-24 09:50:07 -07:00
Jon Staab 125a7e238e Add qr scanner to discover page 2025-09-22 15:56:48 -07:00
Jon Staab 468200b717 Link directly to discover page 2025-09-22 15:48:13 -07:00
Jon Staab bdfcb99781 Show more information about signer type 2025-09-22 15:09:41 -07:00
Jon Staab 38da650861 Add qr code to invite screen 2025-09-22 14:57:43 -07:00
Jon Staab dd006badfc Bring back blossom feature detection 2025-09-22 14:05:57 -07:00
Jon Staab 87e4e3fe5b Catch all upload errors 2025-09-22 11:43:44 -07:00
Jon Staab af3e38254f Fix focus on input list 2025-09-22 11:06:16 -07:00
Jon Staab 70843f54d3 Increase contrast on mention badges in editor 2025-09-22 10:40:54 -07:00
Jon Staab bda75b29b4 Handle bunker login errors better 2025-09-22 10:35:31 -07:00
Jon Staab 750830d593 Bump version again 2025-09-18 14:39:15 -07:00
Jon Staab 3c0f1a1d2f Restore icons 2025-09-18 14:13:08 -07:00
Jon Staab 4253b0ed29 Remove all icons 2025-09-18 14:12:08 -07:00
Jon Staab 3c9b3f23df Upload profile pictures instead of doing base64 2025-09-18 13:43:43 -07:00
Jon Staab e0d83608be Bump version, changelog 2025-09-18 13:09:03 -07:00
Jon Staab a0301d599b Bump welshman, rename stripExifData 2025-09-18 12:17:31 -07:00
Jon Staab 7dcaa0e8d7 Change login icon 2025-09-16 11:06:36 -07:00
Matthew Remmel 129f49bcc7 Compress profile pictures on upload 2025-09-15 10:55:01 -07:00
Jon Staab fc3b68c390 Fix default avatar icon 2025-09-11 16:44:02 -07:00
Jon Staab 52c7df8a15 Default to light mode 2025-09-11 14:47:06 -07:00
Jon Staab ce1c4dd488 Fix some icons 2025-09-11 12:43:18 -07:00
Jon Staab fc6a1a3819 Move alerts to their own page, add direct message alerts 2025-09-11 12:28:54 -07:00
Jon Staab 69bd6d0e70 Use new icons 2025-09-11 08:59:47 -07:00
Jon Staab 6d383d54e8 Fix app image clipping 2025-09-09 10:53:16 -07:00
Jon Staab 998c48b1d3 Wait for thunk errors 2025-09-08 08:34:52 -07:00
Jon Staab 7217d122b5 Re-work invite links 2025-09-08 08:34:52 -07:00
Jon Staab 1c37c5bb3d Make white labeled nav look less bad 2025-09-05 16:21:17 -07:00
Jon Staab e8f785b558 Bump welshman 2025-09-05 11:35:34 -07:00
Matthew Remmel c94d314f6d Use capacitor preferences package instead of localStorage 2025-09-05 11:34:52 -07:00
Jon Staab 2672a8f922 Include instructions in key file 2025-09-05 10:49:20 -07:00
hodlbod 8a8d80d692 Merge pull request #197 from coracle-social/auth-errors
Auth errors
2025-09-04 11:25:30 -07:00
Jon Staab 95698813c6 Monitor relay connections for restricted responses and show error to user 2025-09-04 11:25:12 -07:00
hodlbod 4001e877b4 Merge pull request #193 from coracle-social/trusted-relays
Buffer unsigned events until approved
2025-09-04 11:21:54 -07:00
Jon Staab 99defc6d79 Allow users to opt-in to spaces that strip signatures 2025-09-03 16:36:30 -07:00
Jon Staab a94883089e Rename username to nickname 2025-09-03 16:34:00 -07:00
hodlbod 5ea4aeb75c Merge pull request #186 from coracle-social/flotilla-180-rooms-disappear
Save rooms to local storage
2025-08-27 06:25:08 -07:00
Matthew Remmel 456d111925 Save rooms to local storage 2025-08-27 09:07:32 -04:00
Jon Staab 837ae4b38e Update changelog, bump version 2025-08-26 11:17:38 -07:00
Jon Staab ffbcbf86c3 Bump welshman 2025-08-26 11:08:59 -07:00
Matthew Remmel bcda637192 Merge pull request #182 from coracle-social/flotilla-148-deep-linking
Add mobile deep linking support
2025-08-26 13:37:40 -04:00
Matthew Remmel 72c7dd6126 Add missing data config to android manifest 2025-08-26 13:31:01 -04:00
Matthew Remmel a2a4b3599f Remove temporary code and comments 2025-08-26 13:17:25 -04:00
Matthew Remmel 4955a4f16c Add real values in app association files 2025-08-26 13:16:32 -04:00
Matthew Remmel bb1ff4fb11 Add temporary web event listener for deep link navigation testing in web
browser
2025-08-26 12:43:44 -04:00
Matthew Remmel b81f7c9ed3 Add basic deep link route handling 2025-08-26 12:14:11 -04:00
Matthew Remmel 689cfb6d45 Add placholder changes for deep linking 2025-08-26 10:37:45 -04:00
Jon Staab 9da3141650 Add indicator for who sent the most recent message in a converssation 2025-08-25 16:24:24 -07:00
Jon Staab e4fe18df2f Fix encrypted uploads, show error 2025-08-21 16:06:14 -07:00
Jon Staab ba80ebac63 Add contributing file, rename some files 2025-08-21 15:01:31 -07:00
Jon Staab d4943daa82 Add chat prompt to dashboard 2025-08-19 14:05:02 -07:00
Jon Staab cde03ec0fe Avoid reflow by showing chat thunk status in a toast 2025-08-19 14:03:04 -07:00
Jon Staab 4f6c08f8a2 Build better onboarding 2025-08-18 15:02:17 -07:00
Jon Staab 38e0fc53ad Update wallet to use welshman's session wallet 2025-08-18 13:26:28 -07:00
Jon Staab 2a30ca5306 Bump welshman, drop support for safe area insets 2025-08-06 15:09:22 -07:00
Jon Staab 4a4ea13bef Show relays a note was seen on 2025-08-04 12:32:44 -07:00
Jon Staab 239bd3f31a Remove invite code input from alert add screen 2025-08-01 12:57:29 -07:00
Jon Staab 831ec05012 Filter out non-global chat from global chat 2025-07-31 13:25:40 -07:00
Jon Staab 0cc0598287 Allow tapping on tippy triggers on mobile 2025-07-31 10:25:55 -07:00
Jon Staab 0a5bc618c2 Fix formatting 2025-07-30 16:37:05 -07:00
Jon Staab 069904f07a Only protect events if the relay will authenticate with the user 2025-07-30 16:31:40 -07:00
Jon Staab 03b42c8276 Monitor signer status 2025-07-30 15:54:10 -07:00
Jon Staab 8697cc23be Add signer status, re-work bunker login 2025-07-29 10:53:48 -07:00
Jon Staab 69e1f97e72 Display create at on event info 2025-07-22 10:10:20 -07:00
Jon Staab 3e832af3e4 Update version 2025-07-17 15:41:30 -07:00
Jon Staab 84b8650fa4 Shorten goals title for mobile 2025-07-17 15:40:07 -07:00
Jon Staab 83abb5aa94 Fix chat notifications so they take nip 29 into account 2025-07-17 15:35:49 -07:00
Jon Staab a12eddb47b Fix zaps on mobile 2025-07-17 15:29:26 -07:00
Jon Staab c87166247c Update zapstore.yaml 2025-07-17 15:21:05 -07:00
Jon Staab 037c8cb41b Disable zaps on ios 2025-07-17 14:39:59 -07:00
Jon Staab 79de2e1176 Bump version 2025-07-17 14:30:18 -07:00
Jon Staab d4b026a3ad Add zaps to threads/events 2025-07-15 15:56:55 -07:00
Jon Staab 00f383ff2e Add qr scanning for wallet connect 2025-07-15 15:49:26 -07:00
Jon Staab 6f6bb508db Handle invalid bunker url, update synced stores 2025-07-15 11:34:29 -07:00
Jon Staab e2a0672ca5 load messages in general on room relay 2025-07-09 14:28:07 -07:00
Jon Staab e2a5fe7a79 Fix sidebar overflow 2025-07-09 14:22:59 -07:00
Jon Staab 5d02ae75dc Bump welshman 2025-07-09 14:00:42 -07:00
Jon Staab 2460bbbc83 Fix balance coming from webln 2025-07-09 13:19:33 -07:00
Jon Staab 084d8d931b Load relay selections whenever we see a new pubkey 2025-07-09 09:17:45 -07:00
Jon Staab 6ee4ac1a89 Add funding goals 2025-07-07 15:28:36 -07:00
Jon Staab 1d07097350 Fix some zap bugs 2025-07-07 13:58:43 -07:00
Jon Staab 63d6b362c7 Remove info missing rooms 2025-07-07 12:46:17 -07:00
Jon Staab bfed277ea9 Add zaps 2025-07-04 06:22:19 -07:00
Jon Staab 9e8aa2ef3a show and copy npub 2025-07-02 16:48:44 -07:00
Jon Staab 4bbc0878f7 Bump apple version, add vapid key 2025-07-01 12:53:09 -07:00
Jon Staab 16a3ba2a9b Bump version 2025-06-30 11:08:42 -07:00
Jon Staab 7c11eb8947 Allow mark all as read on desktop 2025-06-30 11:03:02 -07:00
Jon Staab 6bdc8d4d9f Space alerts dialog 2025-06-30 10:41:42 -07:00
Jon Staab b9048936ba Tweak alerts button layout 2025-06-30 09:38:43 -07:00
Jon Staab b9620f4443 Add claim to alert add 2025-06-27 14:36:09 -07:00
Jon Staab f2249fe592 Handle conversations with no room 2025-06-27 09:44:01 -07:00
Jon Staab fd42a0e8d4 Clear badge when opening app 2025-06-27 09:41:30 -07:00
Jon Staab 37d52ba35f Show latest note as conversation 2025-06-27 09:00:43 -07:00
Jon Staab 3037323dc0 Add support for ios push notifications 2025-06-27 08:33:31 -07:00
Jon Staab 5301ef876d Fix notification badge for global chat 2025-06-24 17:36:14 -07:00
Jon Staab aa054d8b1a Fix ContentMention display 2025-06-24 17:23:07 -07:00
Jon Staab 3655790e5f Add fcm push notifications 2025-06-24 14:27:16 -07:00
Jon Staab 6cca823ed4 Get web push working 2025-06-23 11:16:25 -07:00
Jon Staab 18a383edab Update alert form to include push notifications 2025-06-19 10:01:16 -07:00
Jon Staab 43da7d628e Replace bunker with claim on alerts page 2025-06-18 17:02:32 -07:00
Jon Staab 2fae3ca248 Fix broadcasting user profiles when protected 2025-06-16 16:56:59 -07:00
Jon Staab d99ada44f5 Show link url if no title is available 2025-06-16 11:45:05 -07:00
Jon Staab cb0119b9b8 Update welshman 2025-06-16 10:12:24 -07:00
Jon Staab dac9ef8e4e Move some stuff to welshman, broadcast profile updates 2025-06-13 15:17:20 -07:00
Jon Staab 528917b90e Fix sort order of thread comments 2025-06-13 10:14:12 -07:00
Jon Staab a22db78967 rename createEvent to makeEvent 2025-06-10 13:35:57 -07:00
Jon Staab 5718510779 Bump versions 2025-06-09 15:29:13 -07:00
Jon Staab f877dc7fbe Add chat quick link 2025-06-09 15:27:00 -07:00
Jon Staab df03fb1116 Remove old docker workflow 2025-06-09 15:20:09 -07:00
Jon Staab 7455b49f8d Bump version
Build and Publish Docker Image / build-and-push (push) Failing after 9s
2025-06-09 15:15:58 -07:00
Jon Staab ae00eb0b9c Bump welshman and nostr-editor
Build and Publish Docker Image / build-and-push (push) Failing after 2m15s
2025-06-09 15:04:51 -07:00
Jon Staab b82e434c70 Try turning ci off 2025-06-09 14:02:06 -07:00
Jon Staab 576c9c2c95 Bump welshman 2025-06-09 13:48:46 -07:00
Jon Staab cef046b3ae Increase maxLength for recent activity 2025-06-09 13:48:46 -07:00
Jon Staab 18ae6f6044 Use new editor uploads 2025-06-09 13:48:46 -07:00
Jon Staab 664f3c01e0 Bump nostr-tools 2025-06-09 13:48:46 -07:00
Jon Staab 15e82c4e41 Link to frith in SpaceCreateExternal 2025-06-09 13:48:46 -07:00
Jon Staab 397ecf773e Show warning for non-nip29 relays 2025-06-09 13:48:46 -07:00
Jon Staab 45397e7fb8 Show image link if image fails to load 2025-06-09 13:48:46 -07:00
Jon Staab 11aa841241 Add profile room list 2025-06-09 13:48:46 -07:00
Jon Staab cc1c18d55f Update context file 2025-06-09 13:48:46 -07:00
Jon Staab e3fbd69e6e Tweak profiles/search 2025-06-09 13:48:46 -07:00
Jon Staab ac756bf266 tweak relay status component 2025-06-09 13:48:46 -07:00
Jon Staab 8e28ff13e9 Generalize goToMessage 2025-06-09 13:48:46 -07:00
Jon Staab d8b87db784 Flesh out recent activity component 2025-06-09 13:48:46 -07:00
Jon Staab 0b8c6c4a49 Add claude context file and mock up recent activity 2025-06-09 13:48:46 -07:00
Jon Staab 9f4f468bf0 Add tos and pp links 2025-06-09 13:48:46 -07:00
Jon Staab 7563dff621 Move relay status to its own component 2025-06-09 13:48:46 -07:00
Jon Staab f782898b62 Factor space recent activity into its own component 2025-06-09 13:48:46 -07:00
Jon Staab d0601400cd Move space quick links to its own file 2025-06-09 13:48:45 -07:00
Jon Staab d262da39e5 Tweak room search and owner display 2025-06-09 13:48:45 -07:00
Jon Staab 7d617d8399 Add latest note from admin to relay dashboard 2025-06-09 13:48:45 -07:00
Jon Staab d2b7db18af Show socket status on space dashboard 2025-06-09 13:48:45 -07:00
Jon Staab 89c2690254 Add new room dashboard layout 2025-06-09 13:48:45 -07:00
Jon Staab 34945d1c42 Fix chat menu item active state 2025-06-09 13:48:45 -07:00
Jon Staab 43b207c4dc Use kind 15 to send images in DMs 2025-06-09 13:48:45 -07:00
Jon Staab 55efb3fdfd Use encrypted uploads 2025-06-09 13:48:45 -07:00
Jon Staab c4a1ad2e33 Ignore roocode 2025-06-09 13:48:45 -07:00
Jon Staab fd8442c632 Remove space blossom detection 2025-06-09 13:48:45 -07:00
Jon Staab e0875eb9b9 Add minimal style for quotes of chat messages 2025-06-09 13:48:45 -07:00
Jon Staab 962ac7d80c Support copying and pasting npubs better 2025-06-09 13:48:45 -07:00
Jon Staab 5338ee11bc Update changelog 2025-06-09 13:48:45 -07:00
Jon Staab 6d2e9a037d Allow for multiple platform relays 2025-06-09 13:48:45 -07:00
Jon Staab ac8530bd9a Add non-nip29 chat, add leave room 2025-06-09 13:48:45 -07:00
Jon Staab f7d11cf124 Improve group membership detection 2025-06-09 13:48:45 -07:00
Jon Staab 72d85e5740 Unnest nip29 commands 2025-06-09 13:48:45 -07:00
Jon Staab e57b5721f6 Detect nip29 support for create room button 2025-06-09 13:48:45 -07:00
Jon Staab 4ba6c72459 Remove unmanaged groups 2025-06-09 13:48:45 -07:00
Jon Staab c33698c662 Remove general room 2025-06-09 13:48:45 -07:00
Jon Staab cf4e40c4cf Add github action to publish dockerfile 2025-06-09 13:48:45 -07:00
Jon Staab 664da505cd Improve forms for entering invite codes 2025-05-27 15:00:30 -07:00
Jon Staab 573d4e3cfb Add support for customizable accent content color 2025-05-19 16:56:19 -07:00
Jon Staab b2dc41f25b Re-arrange the readme 2025-05-19 15:17:26 -07:00
Jon Staab b3bc0e4957 Add github action to publish dockerfile 2025-05-19 11:54:19 -07:00
Jon Staab 0e79e5b9cc Add dockerfile 2025-05-15 16:20:46 -07:00
Jon Staab 34c7bfcffb Get rid of overries, bump welshman to lockstep versioning 2025-05-15 15:52:17 -07:00
Jon Staab fd9fee8f50 Add indexer, maybe improve safe area support 2025-05-15 10:15:41 -07:00
Jon Staab b14c3ab345 Bump version 2025-05-14 13:52:37 -07:00
Jon Staab 823058e335 Add setting for font size 2025-05-13 14:31:34 -07:00
Jon Staab 60ec6924f3 Fix thunks status layout 2025-05-13 10:35:42 -07:00
Jon Staab 18fc895fcb Tweak navigation to improve white labeled instances 2025-05-13 10:14:20 -07:00
Jon Staab 42295159a0 Update remove-pnpm-overrides to use package version of welshman (hack) 2025-05-13 09:06:53 -07:00
Jon Staab db408ac30d Stop propagation on thunk status 2025-05-12 15:35:13 -07:00
Jon Staab 1ced5689c3 Bump version 2025-05-12 15:19:38 -07:00
Jon Staab 263a803875 Add custom emoji parsing and display 2025-05-12 15:10:24 -07:00
Jon Staab 58afb8fa0c Bump editor 2025-05-12 11:17:13 -07:00
Jon Staab 4aaa19ea1b Apply theme to body so popovers get themed too, make selected popover item more clear 2025-05-12 10:03:29 -07:00
Jon Staab 2f9010cd13 Ignore unnecessary error 2025-05-12 09:01:13 -07:00
Jon Staab 12fcdfcd4f Add light theme and secondary color 2025-05-12 08:48:54 -07:00
Jon Staab 317ab57ed2 Use env instead of env.local 2025-05-12 08:27:46 -07:00
Jon Staab 52ef67740a Move default env to env.template, fix notifier relay/pubkey 2025-05-12 08:27:07 -07:00
Jon Staab 68ebd32e15 Bump welshman 2025-05-09 12:41:02 -07:00
Jon Staab e94aa3c119 Bump version, fix new messages thing 2025-05-09 12:26:05 -07:00
Jon Staab 4d10fe7cc0 Handle broken supported_nips 2025-05-08 11:16:02 -07:00
Jon Staab 841928783b Re-introduce safe inset areas 2025-05-08 11:05:27 -07:00
Jon Staab 6e5e1a0846 Remove safe area inset stuff to re-apply later 2025-05-08 09:11:10 -07:00
Jon Staab d57f4747a6 Tweak errors so that actionable links are rendered 2025-05-07 15:04:35 -07:00
Jon Staab 94a0077b09 Use non-singleton broker 2025-05-07 13:53:58 -07:00
Jon Staab f2eb04adff Bump version 2025-05-07 09:12:17 -07:00
Jon Staab d4d5979a35 Fix missing room images and room overflow in nav 2025-05-07 09:11:00 -07:00
Jon Staab dde6e54657 Add build in production script 2025-05-06 18:26:48 -07:00
Jon Staab 698a7513b8 Tweak some gradle stuff 2025-05-06 18:07:30 -07:00
Jon Staab ea3f5a6779 Bump version 2025-05-06 17:06:18 -07:00
Jon Staab f5fce8e2e7 Bump welshman and signer plugin 2025-05-06 10:34:14 -07:00
Jon Staab 46b5c01c49 Allow use of cleartext relays on native 2025-05-06 09:50:05 -07:00
Jon Staab dd069329ee Add timezone and locale to alerts 2025-05-05 15:39:07 -07:00
Jon Staab c1b52b66ff Use lib version of date functions 2025-05-05 10:11:02 -07:00
Jon Staab 5873e8aa60 Fix modal stuff 2025-04-29 15:20:40 -07:00
Jon Staab c582082816 Fix link detail for authenticated images 2025-04-29 12:30:01 -07:00
Jon Staab 6ddba63ff9 Use space as blossom server if supported 2025-04-29 12:26:29 -07:00
Jon Staab 5a7750a91b Use user blossom server list for settings, add InputList 2025-04-29 11:04:39 -07:00
Jon Staab 8c71b7d9b9 Update welshman 2025-04-29 09:56:52 -07:00
Jon Staab b5a28c71ad Support auth-protected images 2025-04-28 15:46:48 -07:00
Jon Staab ccdd18a863 Fill in default email for alerts 2025-04-28 12:28:39 -07:00
Jon Staab 2244ecad9b Update alerts to use new anchor 2025-04-28 09:48:09 -07:00
Jon Staab da2457da9f Use new relay getters 2025-04-25 10:41:38 -07:00
Jon Staab c18b29e7d6 Update welshman stuff, fix bug in makeFeed 2025-04-24 12:35:41 -07:00
Jon Staab 3a954201ce Tweak boot, stop saving alert events 2025-04-23 11:05:28 -07:00
Jon Staab c8bc8ee8bf Fix thunk indicator 2025-04-16 14:19:09 -07:00
Jon Staab 8c3e52ce8c Update storage adapters 2025-04-16 14:08:58 -07:00
Jon Staab 303b8967e9 Remove aliases, their time has not yet come 2025-04-16 10:36:21 -07:00
Jon Staab f3debe6c02 Use new ALIAS kind 2025-04-15 15:45:48 -07:00
Jon Staab 374ca7f265 Add per-url aliases 2025-04-15 15:07:54 -07:00
Jon Staab 91689e5b90 Optionally protect profiles 2025-04-15 09:36:59 -07:00
Jon Staab a64eaba45c Fix modal flash 2025-04-14 17:13:16 -07:00
Jon Staab 394a1e7d30 Update to new thunk stuff 2025-04-14 16:50:48 -07:00
Jon Staab d5b1fab1e7 Tweak data loading 2025-04-11 14:44:27 -07:00
Jon Staab 10a1e6e640 Update welshman session stuff 2025-04-11 11:51:15 -07:00
Jon Staab 84af4d2d8e Update welshman stuff again 2025-04-11 09:27:19 -07:00
Jon Staab acddff79f0 Improve loading a bit 2025-04-11 08:41:50 -07:00
Jon Staab 489707b9b2 Switch to pnpm, use new welshman stuff 2025-04-09 15:32:35 -07:00
Jon Staab 33902dbefe Make calendar window smaller to avoid tag limits 2025-04-03 15:56:37 -07:00
Jon Staab 1b318a7a52 Fix reactions on mobile 2025-04-03 15:40:52 -07:00
Jon Staab b6a4b38d14 Make relays configurable 2025-04-03 15:35:56 -07:00
Jon Staab a3eb6d52c0 Fix nip46 signer connect 2025-03-24 12:40:47 -07:00
Jon Staab d2c537d275 Refactor login, pass bunker to alerts 2025-03-20 13:00:07 -07:00
Jon Staab 9eefd6600d Add handler for alerts 2025-03-20 09:38:57 -07:00
Jon Staab ad034b1641 Tweak layout css 2025-03-19 11:22:57 -07:00
Jon Staab d94860014c Fix chat spacing 2025-03-19 09:56:00 -07:00
Jon Staab 33af39ee93 Add calendar event editing 2025-03-18 15:36:52 -07:00
Jon Staab 1d56a2193d Clean up calendar header 2025-03-17 09:53:14 -07:00
Jon Staab 75905e4652 Take a guess at fixing android keyboard issue 2025-03-07 09:01:47 -08:00
Jon Staab d07b9cde5f Tweak spacing 2025-03-04 17:39:54 -08:00
Jon Staab d8a9cc5a7e Fix sizing for big chat inputs 2025-03-04 12:53:38 -08:00
Jon Staab 863d11352f Bump versions 2025-03-04 11:28:41 -08:00
Jon Staab b4cc770cdf Update changelog 2025-03-04 11:20:24 -08:00
Jon Staab 901e56a625 Tweak settings page, hide alerts 2025-03-04 10:58:14 -08:00
Jon Staab 479fed34f7 Fix chat layout on ios 2025-03-04 10:52:27 -08:00
Jon Staab 81d7b08aed Fix profile suggestions 2025-03-04 10:47:58 -08:00
Jon Staab a582b1ea73 Apply layout changes to chat 2025-03-04 10:20:06 -08:00
Jon Staab 1c0b2a09df ellipsize page bar title 2025-03-04 10:00:24 -08:00
Jon Staab 3a42a1b560 Rework css on room view to avoid losing input visibility 2025-03-04 09:49:56 -08:00
Jon Staab db203bf00d Move page bar closer to top of screen 2025-03-03 17:10:17 -08:00
Jon Staab ffb36af734 Make analytics and error reporting optional 2025-03-03 15:09:58 -08:00
Jon Staab b399fa8dcc Replace long press with tap target 2025-03-03 13:59:38 -08:00
Jon Staab 5bba5959f7 Attempt to fix keyboard placement, wait for connection 2025-03-03 13:23:44 -08:00
Jon Staab 2ad65e394e Remember user minute selection 2025-03-03 13:04:12 -08:00
Jon Staab 345b20bf5d Fix nevent hints for url-specific stuff 2025-03-03 12:10:47 -08:00
Jon Staab b9fb251b32 Randomize subscription minute 2025-02-27 09:33:40 -08:00
Jon Staab dd9a9c0df2 Add status to alert items 2025-02-25 13:36:32 -08:00
Jon Staab 115b5f9fbe Extend timeout for setChecked 2025-02-24 13:40:26 -08:00
Jon Staab 3ad7dcfeb4 Ignore some files 2025-02-19 11:13:38 -08:00
Jon Staab 60d107aed2 Fix some state stuff, snapshot things in the right places 2025-02-18 17:15:41 -08:00
Jon Staab 08d8d45ecb Refactor confirm to avoid passing closures 2025-02-18 09:03:10 -08:00
Jon Staab c40e8ce1a7 Fix reactions on mobile 2025-02-17 17:33:21 -08:00
Jon Staab 993bf8d2e6 Bump gradle build number 2025-02-14 16:20:16 -08:00
Jon Staab c3c65c3970 Use in-app onboarding on all native platforms 2025-02-14 16:07:40 -08:00
Jon Staab a5b868cd56 Update changelog 2025-02-14 16:02:11 -08:00
Jon Staab 8fcc56a408 Bump version 2025-02-14 16:00:18 -08:00
Jon Staab c8dfbc936b Spruce up nstart, add profile deletion 2025-02-14 15:59:20 -08:00
Jon Staab f1e76a1ed1 Bump versions, limit key generation to ios 2025-02-14 12:18:52 -08:00
Jon Staab 6ecc3e6770 Improve discover page 2025-02-14 12:14:00 -08:00
Jon Staab b05c408977 Move loadUserData to requests 2025-02-14 11:12:19 -08:00
Jon Staab e484c3cb00 Bump versions 2025-02-14 10:56:00 -08:00
Jon Staab 69d0e11ba4 Add nip 01 login flow to mobile 2025-02-14 10:53:36 -08:00
Jon Staab 27d9d4fff1 Update changelog 2025-02-13 16:32:34 -08:00
Jon Staab c089812363 Show spinner when joining room 2025-02-13 15:34:14 -08:00
Jon Staab 07dd1e97dc Fix long-running subscriptions clogging things up 2025-02-13 14:50:03 -08:00
Jon Staab 7f6a1bff34 Re-work threads page, fix some iphone bugs 2025-02-13 10:52:00 -08:00
Jon Staab 7d1310722a Factor out calendar event component, render calendar event notes better 2025-02-11 16:00:14 -08:00
Jon Staab cb57710654 Clean up quotes/depth 2025-02-11 15:37:55 -08:00
Jon Staab c74c116667 Fix page bar margin #112 2025-02-11 15:16:24 -08:00
Jon Staab 0ba55f2387 Attempt to fix new messages button #114 2025-02-11 11:49:17 -08:00
Jon Staab 622214713b replace state when navigating from space menu 2025-02-11 11:42:49 -08:00
Jon Staab d8cf48381b Build before other stuff 2025-02-06 12:52:42 -08:00
Jon Staab 7dc7b5abeb Bump android version 2025-02-06 12:43:18 -08:00
Jon Staab 324db6a9e8 Bump welshman 2025-02-06 12:25:55 -08:00
Jon Staab 466541caf5 Fix marker in chat 2025-02-06 11:39:51 -08:00
Jon Staab 19f657e348 Make sharing indicator nicer 2025-02-06 11:33:01 -08:00
Jon Staab 98a0511b34 Update changelog 2025-02-06 11:17:32 -08:00
Jon Staab 0ec620dff9 Make calendar event detail nice 2025-02-06 11:12:15 -08:00
Jon Staab 1301c2c74f Rename ThreadReply to EventReply 2025-02-06 10:24:31 -08:00
Jon Staab 7848859153 Make event menu/share generic 2025-02-06 10:14:29 -08:00
Jon Staab 2d67a9bcf6 Add shared EventActions component 2025-02-06 10:00:25 -08:00
Jon Staab a7e9318819 Add shared EventActivity component 2025-02-06 09:53:50 -08:00
Jon Staab d66371d573 Break out a few shared sub-components 2025-02-06 09:39:23 -08:00
Jon Staab 5684d1a9cf Add calendar actions, menus, etc 2025-02-06 09:29:30 -08:00
Jon Staab fa4bc6894f Fix a couple calendar bugs 2025-02-06 08:55:01 -08:00
Jon Staab 72919cb1c2 Derive all the things 2025-02-06 08:50:50 -08:00
Jon Staab 6a3a02bc34 Handle scrolling on calendar 2025-02-05 17:05:41 -08:00
Jon Staab db69c56f57 Add makeCalendarFeed 2025-02-05 16:26:22 -08:00
Jon Staab a0c6e46184 Use unix days instead of time hashes 2025-02-05 15:15:50 -08:00
Jon Staab 65aabf5feb Rework datetime input 2025-02-05 15:05:58 -08:00
Jon Staab 131cc99c47 Flesh out EventItem 2025-02-05 13:02:51 -08:00
Jon Staab 5909b593ab Fix bugs, add timehash 2025-02-05 10:47:56 -08:00
Jon Staab f0b2b7c8b3 Re-work datetime input 2025-02-05 08:57:31 -08:00
Jon Staab 24a7fa4174 Add calendar to navigation 2025-02-05 08:55:39 -08:00
Jon Staab 3f2813b63b Add missing editor content 2025-02-05 08:54:04 -08:00
Jon Staab 3e214881a3 Fix warning, hide images in quotes 2025-02-05 08:53:26 -08:00
Jon Staab af171bd2c9 Move EditorContent to editor directory 2025-02-05 08:17:51 -08:00
Jon Staab 565ccb399a Remove editor, use welshman editor again 2025-02-04 20:29:12 -08:00
Jon Staab fd99866b1e Replace svelte components with node views 2025-02-04 20:01:36 -08:00
Jon Staab 506276f594 Fix suggestions component 2025-02-04 19:39:26 -08:00
Jon Staab d4df23545d Re-write suggestions 2025-02-04 19:00:48 -08:00
Jon Staab e53d2eb8da Small bugs/copy changes 2025-02-04 14:21:21 -08:00
Jon Staab 22cbb9fe1c Handle thunks in feeds 2025-02-04 14:06:05 -08:00
Jon Staab fedc99b0f0 Create new EditorContent component 2025-02-03 20:57:47 -08:00
Jon Staab 7d4ba6c806 Use snapshots in some places 2025-02-03 20:43:18 -08:00
Jon Staab a0e97d5e5b Finish svelte 5 migration 2025-02-03 19:28:29 -08:00
Jon Staab 24045a7e2a Fix more stuff, particularly event handlers 2025-02-03 17:21:46 -08:00
Jon Staab 8d3433b167 Migrate more stuff 2025-02-03 16:37:14 -08:00
Jon Staab 0f705c459a Fix some small issues 2025-02-03 15:50:19 -08:00
Jon Staab 08ee07d157 Fix some type errors 2025-02-03 15:40:00 -08:00
Jon Staab cfbff94b4c Fix self-closing tags 2025-02-03 15:01:42 -08:00
Jon Staab 34477e8ea6 Upgrade to svelte 5 2025-02-03 14:36:09 -08:00
Jon Staab eab0ea4eef Upload sourcemaps by hash 2025-02-03 12:37:17 -08:00
Jon Staab 8ec4d9c548 Update lockfile 2025-02-03 09:12:14 -08:00
Jon Staab 9defe20f91 Fix signer plugin 2025-02-03 09:01:41 -08:00
Jon Staab 614cdcdf53 Fix p-tagging dms 2025-02-03 08:59:45 -08:00
Jon Staab bcd94ee75e Make ios with notches prettier 2025-01-31 17:40:14 -08:00
Jon Staab def6de321c Some ios stuff 2025-01-31 17:09:46 -08:00
Jon Staab 6c7c533637 Fix QR code on iphone 2025-01-31 14:14:42 -08:00
Jon Staab f0207b35d0 Update capacitor, get ios running 2025-01-31 13:14:29 -08:00
Jon Staab 858e04d7fa tiny change 2025-01-31 09:36:46 -08:00
Jon Staab b7dcb77378 Rename njump -> nstart 2025-01-29 07:52:24 -08:00
Jon Staab cee6c3c164 Bump versions 2025-01-28 19:22:57 -08:00
Jon Staab 06d0ae2798 Trim tiptap css 2025-01-28 16:23:19 -08:00
Jon Staab b129ef4242 Add build hash 2025-01-28 14:51:33 -08:00
Jon Staab 48a45f3a3a Add media server settings 2025-01-28 14:44:43 -08:00
Jon Staab ce1fb396e3 Add button to scroll to new messages in channel 2025-01-28 14:19:46 -08:00
Jon Staab e95c57bcb7 Replace nsec.app signup with njump.me 2025-01-28 13:04:37 -08:00
Jon Staab 414f5a5ace Update changelog 2025-01-28 12:33:35 -08:00
Jon Staab a331d24bb1 Bump welshman 2025-01-28 12:28:26 -08:00
Jon Staab fb53e53411 Add reply to long press menu 2025-01-28 09:47:11 -08:00
Jon Staab 1e7e439e3f Bump version 2025-01-28 09:30:17 -08:00
Jon Staab 3368cba1be Bump welshman/app 2025-01-28 09:26:11 -08:00
Jon Staab 4f0579bb7f Fix missing compose input, handle parents differently 2025-01-28 09:23:51 -08:00
Jon Staab 08e80262a4 Bump welshman, rework channel loading 2025-01-28 08:13:20 -08:00
Jon Staab e10b83bed8 Improve data loading a bit 2025-01-24 13:35:09 -08:00
Jon Staab fa17c398ca Make deploy documentation more clear 2025-01-24 09:49:14 -08:00
Jon Staab e0840f24dd Drop support for legacy messages 2025-01-24 09:36:24 -08:00
Jon Staab 8e38271534 Attempt to fix broken android 2025-01-20 08:40:37 -08:00
Jon Staab 86928fc12c Bump welshman 2025-01-17 15:01:05 -08:00
Jon Staab e15fb3ce9c Update app icon 2025-01-17 09:08:55 -08:00
Jon Staab bf1ab5f0ee Bump version 2025-01-17 05:30:08 -08:00
Jon Staab 59568f95f1 Update logo 2025-01-16 15:26:54 -08:00
Jon Staab 75d52e7e17 Outsource terms/privacy 2025-01-16 14:54:43 -08:00
Jon Staab bdb5d3dfaa Update changelog 2025-01-16 08:46:51 -08:00
Jon Staab c387b65460 Bump version to 0.2.3 2025-01-16 08:41:20 -08:00
Jon Staab 01c4219922 Add reviewkey auth bypass, remove note to self 2025-01-15 15:48:39 -08:00
Jon Staab 9ca4440038 Add terms/privacy notice to landing 2025-01-15 14:05:23 -08:00
Jon Staab d6cc414f41 Add terms and privacy 2025-01-15 13:56:04 -08:00
Jon Staab 7ccb2949a9 Update gitignore 2025-01-15 13:41:15 -08:00
Jon Staab 8d4e657af5 Tweak avatar again 2025-01-15 11:42:54 -08:00
Jon Staab 4886650dfa Add mark all read 2025-01-15 11:07:21 -08:00
Jon Staab e36e6093e9 Add avatar fallback 2025-01-15 10:56:56 -08:00
Jon Staab edd6e5c8fc Add send button 2025-01-15 09:10:48 -08:00
Jon Staab be7a42d951 Add reports to channel messages 2025-01-15 07:40:28 -08:00
Jon Staab af91fe129b Accommodate onion urls 2025-01-14 15:58:38 -08:00
Jon Staab 6fcf0e7f12 Fix migration 2025-01-14 15:03:36 -08:00
Jon Staab b6defe59a8 Improve loading and notifications 2025-01-02 16:58:04 -08:00
Jon Staab f618e4e1f3 Fix tiptap styling 2025-01-02 16:12:46 -08:00
Jon Staab 5253980cdc Update changelog 2025-01-02 15:59:51 -08:00
1909 changed files with 53901 additions and 22863 deletions
+7
View File
@@ -1,3 +1,10 @@
--ignore-dir=.svelte-kit
--ignore-dir=android
--ignore-dir=target
--ignore-dir=build
--ignore-dir=ios/DerivedData
--ignore-dir=ios/App/App/public
--ignore-dir=ios/App/Pods
--ignore-file=match:.svg
--ignore-file=match:package-lock.json
+12
View File
@@ -0,0 +1,12 @@
node_modules
android
ios
build
# Git
.git
.gitignore
# Env files (keep .env for build; exclude local overrides)
.env.local
.env.*.local
+19 -5
View File
@@ -1,10 +1,24 @@
VITE_DEFAULT_PUBKEYS=fe7f6bc6f7338b76bbf80db402ade65953e20b2f23e66e898204b63cc42539a3,391819e2f2f13b90cac7209419eb574ef7c0d1f4e81867fc24c47a3ce5e8a248,84dee6e676e5bb67b4ad4e042cf70cbd8681155db535942fcc6a0533858a7240,dace63b00c42e6e017d00dd190a9328386002ff597b841eb5ef91de4f1ce8491,82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2,58c741aa630c2da35a56a77c1d05381908bd10504fdd2d8b43f725efa6d23196,eeb11961b25442b16389fe6c7ebea9adf0ac36dd596816ea7119e521b8821b9e,b676ded7c768d66a757aa3967b1243d90bf57afb09d1044d3219d8d424e4aea0,61066504617ee79387021e18c89fb79d1ddbc3e7bff19cf2298f40466f8715e9,3f770d65d3a764a9c5cb503ae123e62ec7598ad035d836e2a810f3877a745b24,6389be6491e7b693e9f368ece88fcd145f07c068d2c1bbae4247b9b5ef439d32,97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322
VITE_BURROW_URL=
VITE_PLATFORM_URL=https://flotilla.social
VITE_DEFAULT_PUBKEYS=06639a386c9c1014217622ccbcf40908c4f1a0c33e23f8d6d68f4abf655f8f71,266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5,391819e2f2f13b90cac7209419eb574ef7c0d1f4e81867fc24c47a3ce5e8a248,3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d,3f770d65d3a764a9c5cb503ae123e62ec7598ad035d836e2a810f3877a745b24,55f04590674f3648f4cdc9dc8ce32da2a282074cd0b020596ee033d12d385185,58c741aa630c2da35a56a77c1d05381908bd10504fdd2d8b43f725efa6d23196,61066504617ee79387021e18c89fb79d1ddbc3e7bff19cf2298f40466f8715e9,6389be6491e7b693e9f368ece88fcd145f07c068d2c1bbae4247b9b5ef439d32,63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed,6e75f7972397ca3295e0f4ca0fbc6eb9cc79be85bafdd56bd378220ca8eee74e,76c71aae3a491f1d9eec47cba17e229cda4113a0bbb6e6ae1776d7643e29cafa,7fa56f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751ac194,82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2,84dee6e676e5bb67b4ad4e042cf70cbd8681155db535942fcc6a0533858a7240,97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322,b676ded7c768d66a757aa3967b1243d90bf57afb09d1044d3219d8d424e4aea0,dace63b00c42e6e017d00dd190a9328386002ff597b841eb5ef91de4f1ce8491,eeb11961b25442b16389fe6c7ebea9adf0ac36dd596816ea7119e521b8821b9e,fe7f6bc6f7338b76bbf80db402ade65953e20b2f23e66e898204b63cc42539a3
VITE_DEFAULT_BLOSSOM_SERVERS=https://blossom.primal.net/
VITE_POMADE_SIGNERS=https://pomade.coracle.social,https://pomade.fiatjaf.com,https://pomade.nostrver.se,https://pomade.scuttle.works
VITE_PLATFORM_URL=https://app.flotilla.social
VITE_PLATFORM_TERMS=https://flotilla.social/terms
VITE_PLATFORM_PRIVACY=https://flotilla.social/privacy
VITE_PLATFORM_NAME=Flotilla
VITE_PLATFORM_LOGO=static/flotilla.png
VITE_PLATFORM_RELAY=
VITE_PLATFORM_LOGO=static/logo.png
VITE_PLATFORM_RELAYS=
VITE_PLATFORM_ACCENT="#7161FF"
VITE_PLATFORM_SECONDARY="#EB5E28"
VITE_PLATFORM_DESCRIPTION="Flotilla is nostr — for communities."
VITE_PUSH_SERVER=https://nps.flotilla.social/
VITE_PUSH_BRIDGE=wss://npb.coracle.social/
VITE_BLOCKED_RELAYS=brb.io,relay.nostr.band,nostr.mutinywallet.com,feeds.nostr.band,nostr.zbd.gg,wot.utxo.one,blastr.f7z.xyz,relay.current.fyi
VITE_INDEXER_RELAYS=purplepag.es,relay.damus.io,indexer.coracle.social
VITE_DEFAULT_RELAYS=relay.damus.io,relay.primal.net,nostr.mom
VITE_DEFAULT_SEARCH_RELAYS=relay.ditto.pub,antiprimal.net,relay.vertexlab.io
VITE_DEFAULT_MESSAGING_RELAYS=auth.nostr1.com,relay.keychat.io,relay.ditto.pub
VITE_SIGNER_RELAYS=relay.nsec.app,ephemeral.snowflare.cc,bucket.coracle.social
VITE_VAPID_PUBLIC_KEY=BIt2D4BdgdbCowD_0d3Np6GbrIGHxd7aIEUeZNe3hQuRlHz02OhzvDaai0XSFoJYVzSzdMjdyW-QhvW9_yq8j4Y
VITE_THUMBNAIL_URL=https://vthumbs.coracle.social
VITE_GLITCHTIP_API_KEY=
GLITCHTIP_AUTH_TOKEN=
+15 -1
View File
@@ -1,3 +1,17 @@
src/assets
android
.claude
target
build
.idea
.gradle
*.png
*.ttf
gradlew*
_app
release
ios/DerivedData/
ios/App/Pods/
android/capacitor-cordova-android-plugins
android/app/src/androidTest
android/app/src/test
node_modules
+1 -1
View File
@@ -1 +1 @@
package-lock.json -diff
pnpm-lock.yaml -diff
+50
View File
@@ -0,0 +1,50 @@
name: Docker
on:
push:
branches: [master]
env:
REGISTRY: ghcr.io
IMAGE_NAME: coracle-social/flotilla
jobs:
build-and-push-image:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
driver: docker-container
- name: Build and push Docker image
id: push
uses: docker/build-push-action@v5
with:
context: .
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
+62 -12
View File
@@ -1,17 +1,6 @@
node_modules
# Output
.output
.vercel
/.svelte-kit
/build
# OS
.DS_Store
Thumbs.db
# Env
.env.local
.env.*.local
# Vite
vite.config.js.timestamp-*
@@ -26,3 +15,64 @@ static/apple-touch-icon-180x180.png
static/maskable-icon-512x512.png
src/assets/icons/*.webp
manifest.webmanifest
# Capacitor
ios/App/public/
ios/App/Pods/
ios/App/Podfile.lock
ios/DerivedData/
android/app/src/main/assets/public/
# Web/JavaScript
node_modules/
.pnpm-store/
build/
.svelte-kit/
.next/
# Rust/Tauri
*target/
src-tauri/binaries/
# iOS
ios/App/App/public
ios/DerivedData
xcuserdata/
*.xcworkspace/
*.mode1v3
*.mode2v3
*.perspectivev3
*.pbxuser
*.xccheckout
*.moved-aside
*.hmap
*.ipa
*.xcuserstate
*.dSYM.zip
*.dSYM
# Android
*.apk
*.aab
*.ap_
*.dex
*.class
bin/
gen/
out/
.gradle/
local.properties
proguard/
google-services.json
GoogleService-Info.plist
# IDEs and editors
.roo
.idea/
.vscode/
.claude/
# OS generated
.DS_Store
Thumbs.db
package-lock.json
+8 -2
View File
@@ -1,2 +1,8 @@
npm run lint
npm run check
pnpm run lint
pnpm run check
if [[ ! -z $(cat package.json | grep 'link:') ]]; then
echo "Some packages are linked to local files!"
exit 1
fi
+1
View File
@@ -0,0 +1 @@
lts/jod
+1 -1
View File
@@ -5,6 +5,6 @@
"svelteSortOrder": "options-styles-scripts-markup",
"arrowParens": "avoid",
"bracketSpacing": false,
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
"plugins": ["prettier-plugin-tailwindcss", "prettier-plugin-svelte"],
"overrides": [{"files": "*.svelte", "options": {"parser": "svelte"}}]
}
+268
View File
@@ -0,0 +1,268 @@
## Project Overview
Flotilla is a Nostr "relays as groups" community chat client. It implements NIP-29 (relay-based groups) to create Discord-like spaces (servers) and rooms (channels).
**Tech Stack:**
- SvelteKit 5.48+ with TypeScript 5.9+
- Capacitor for cross-platform (Web/PWA, Android, iOS)
- TailwindCSS + DaisyUI for styling
- Welshman library suite for Nostr protocol
- IndexedDB for local storage
- Vite for building
**Key Concepts:**
- **Spaces** - Relays used as community groups (like Discord servers)
- **Rooms** - NIP-29 groups within spaces (like Discord channels), identified by `h`
- **Chats** - Direct message conversations (NIP-04/NIP-44 encrypted)
## Architecture & Dependency Graph
The project follows a **strict acyclic dependency hierarchy**:
```
routes/ (top layer - can depend on anything)
app/components/ (can depend on app/* and lib/*)
app/core/ & app/util/ (can only depend on lib/*)
lib/ (can only depend on external libraries)
external libraries (bottom layer)
```
**Import Ordering Convention (CRITICAL):**
Always sort imports by dependency level:
1. Third-party libraries first
2. Then `lib/` imports
3. Then `app/` imports
Example:
```typescript
import {derived} from "svelte/store"
import {throttle} from "throttle-debounce"
import {Dialog} from "$lib/components"
import {repository} from "$app/core/state"
```
## File Structure
```
src/
├── lib/ # Generic reusable code
│ ├── components/ # 38 UI components (Button, Dialog, etc.)
│ ├── html.ts # DOM utilities
│ ├── indexeddb.ts # IndexedDB helpers
│ └── util.ts # Generic utilities
├── app/
│ ├── core/
│ │ ├── state.ts # State management, stores, constants (687 lines)
│ │ ├── commands.ts # Publishing events and other write operations (440+ lines)
│ │ ├── requests.ts # Loading data from network (191 lines)
│ │ ├── sync.ts # Data synchronization (296 lines)
│ │ └── storage.ts # IndexedDB setup
│ │
│ ├── util/
│ │ ├── notifications.ts # Push notifications (731 lines)
│ │ ├── policies.ts # Relay policies
│ │ ├── routes.ts # Routing helpers
│ │ ├── modal.ts # Modal management
│ │ ├── toast.ts # Toast notifications
│ │ ├── theme.ts # Theme switching
│ │ └── keyboard.ts # Keyboard handling
│ │
│ ├── editor/ # Rich text editor config
│ │ ├── index.ts # TipTap setup with Nostr integration
│ │ ├── EditorContent.svelte
│ │ └── MentionNodeView.ts
│ │
│ └── components/ # 188 app-specific components
│ ├── Space*.svelte # Space/relay management
│ ├── Room*.svelte # Room/channel management
│ ├── Chat*.svelte # Direct messaging
│ ├── Profile*.svelte # User profiles
│ ├── Thread*.svelte # Threaded posts
│ └── ...
├── routes/ # SvelteKit file-based routing
│ ├── +layout.svelte # Root layout (sync logic here)
│ ├── spaces/ # Space management
│ │ └── [relay]/ # Specific space
│ │ ├── chat/ # Space chat
│ │ ├── threads/ # Thread posts
│ │ ├── calendar/ # Events
│ │ └── [h]/ # Specific room (h = room id)
│ ├── chat/ # Direct messages
│ ├── settings/ # User settings
│ └── [bech32]/ # Bech32 entity viewer
├── assets/icons/ # ~1,277 SVG icons
├── app.html # HTML template
├── app.css # Global styles
└── types.d.ts # Type definitions
```
## State Management
**Core Principles:**
- Use Svelte 4 **stores** for all state (NOT runes outside UI components)
- Most global state flows through Welshman's `repository` (unidirectional)
- Query state using `deriveEventsMapped` or `deriveProfile` etc
- Update state by publishing events via `publishThunk`
**Thunks:**
- Reduce UI latency by handling signatures and sending in background
- Return status that should be displayed to user
- Allow cancellation and error handling
- Immediately publish to local repository for optimistic updates
## Nostr Integration
**Welshman Library Suite:**
- `@welshman/app` - High-level state (pubkey, signer, repository, tracker)
- `@welshman/net` - Network layer (Pool, Socket, load, pull, request)
- `@welshman/store` - Svelte integration (deriveEventsMapped, etc.)
- `@welshman/util` - Event utilities (kinds, tags, validation)
- `@welshman/signer` - Signing abstraction (NIP-01, NIP-07, NIP-46)
- `@welshman/router` - Relay routing (inbox/outbox model)
- `@welshman/editor` - Rich text editor with Nostr
- `@welshman/content` - Content parsing
- `@welshman/feeds` - Feed management
**Key NIPs Implemented:**
- NIP-01: Basic protocol
- NIP-44/59/17: Encrypted DMs
- NIP-07: Browser extension signing
- NIP-19: Bech32 encoding
- NIP-29: Relay-based Groups
- NIP-42: Relay authentication
- NIP-43: Relay membership
- NIP-46: Nostr Connect (remote signing)
- NIP-57: Lightning Zaps
## Development Conventions
**Component Parameterization:**
- Only pass entity identifiers (`url` for spaces, `h` for rooms)
- Derive all other data inside the component from identifiers
- Example: Don't pass `members` prop, derive it from `h` inside component
**CRITICAL Code Style Guidelines:**
- **No `null`** - only use `undefined`
- Svelte 5 runes (`$state`, `$derived`, `$effect`) only in UI components
- TailwindCSS and DaisyUI styling
- Only add comments for really weird stuff
- Do not call functions in components unless a parameter is reactive. Instead, use a svelte store or rune to make it reactive.
- Do not use `any`. If there are type errors related to `unknown`, they are likely because the upstream definition of the data is incorrect.
- When dynamically building classes, use `cx` from `classnames` rather than embedded ternaries or svelte 4's old `class:` syntax.
- When creating forms, use `FieldInline` or `Field` instead of custom elements/tailwindcss
- Do not define svelte event handlers inline, instead name them and put them in the script section of templates
- Avoid using `as`, except where necessary. Instead, annotate function parameters, and ensure upstream values are typed correctly.
- Instead of `getTag(tagName, event.tags)?.[1] || ""`, use `getTagValue(tagName, event.tags)`
**Human-First Simplicity (Jon Staab Style):**
- Prefer direct, readable code over layered abstractions.
- Do not add indirection (extra helpers, wrappers, stores, or derived state) unless it removes real repeated complexity.
- Reuse existing Welshman and Flotilla primitives before introducing new utilities or dependencies.
- Favor linear control flow and explicit naming over clever patterns.
- Remove defensive checks that do not apply in this runtime model.
- When two approaches work, pick the one that feels more human and easier to maintain.
## Common Tasks
### Adding a New Component
1. Determine if it's generic (`lib/components/`) or app-specific (`app/components/`)
2. Follow naming convention: `PascalCase.svelte`
3. Import in dependency order (3rd party → lib → app)
4. Use stores for state, runes only for UI reactivity
### Creating a New Route
1. Add to `src/routes/` following SvelteKit conventions
2. Use `+page.svelte` for page component
3. Use `+layout.svelte` for shared layouts
4. Top-level sync logic goes in root `+layout.svelte`
### Loading Data from Network
1. Use utilities from `app/core/requests.ts`
2. Or create derived stores in `app/core/state.ts`
3. Use `load`, `pull`, or `request` from `@welshman/net`
### Publishing Events
1. Create `make*` function to build event template
2. Create `publish*` function using `publishThunk`
3. Display thunk status to user (for cancel/error handling)
4. These go in in `app/core/commands.ts`
### Managing Modals/Toasts
- Import from `app/util/modal.ts` or `app/util/toast.ts`
- Pass component objects with parameters
- Use `$state.snapshot` if calling component might unmount
## Development Workflow
Agents should not run the dev server or build the app. Instead, use the following commands:
```bash
pnpm run format # Format changed files
pnpm run lint # Check formatting and linting
pnpm run check # Type check
```
**Welshman Development:**
- Clone welshman to parent directory
- Use `./link_deps` script to link local welshman packages
- Avoid committing `pnpm.overrides` changes
**Git Workflow:**
- `master` branch auto-deploys to production
- Work on feature branches based on `dev` branch
- Pre-commit hooks run lint/typecheck automatically
## Environment Variables
See `.env.template` for all options.
## Important Files to Reference
- **src/app/core/state.ts** - All stores and constants
- **src/app/core/sync.ts** - Data synchronization
- **src/app/core/requests.ts** - Utilities for requesting data
- **src/app/core/commands.ts** - Publishing patterns
- **src/app/util/notifications.ts** - Notification badges and push notifications
- **src/routes/+layout.svelte** - Top-level sync logic
## Mobile Development
**Capacitor Integration:**
- Android: Full support, APK builds via `pnpm run release:android`
- iOS: Full support (zaps disabled due to App Store policy)
- PWA: Progressive Web App with service worker
**Native Features:**
- Push notifications (FCM/APNs)
- Deep linking (nostr: and https: URLs)
- Native signing plugin
- Keyboard management
- Safe area handling
- Badge management
+434
View File
@@ -1,5 +1,439 @@
# Changelog
# 1.7.4
* Fix safe area inset for FAB
# 1.7.3
* Add native share support for space invites
* Stop sending duplicate requests per room
* Add more robust thumbnail url generation
* Make space reordering discoverable with smoother drag animation
* Improve relay member list
* Add room mentions and clickable room/relay refs
* Support native clipboard image paste on mobile
* publish kind 9 quote after room content creation for cross-client interoperability
* Improve feed pagination logic and performance
* Support Aegis URL scheme for NIP-46 login
* Various UI and bug fixes
* Raise message size limit in chat
* Fix realtime updates for room members and admins
* Add video to calls
* Remove follow graph building
* Add start chat FAB
* Add drafts
* Redesign toast notifications
* Remove room/space leave indications
* Hide report badge for non-admin users
* Add polls
* Add search to recent activity page
* Fix notification badge on mobile nav
* Change audio devices in call
# 1.7.2
* Fix race condition in nip 46
* Remove duplicate spaces button
* Combine discover and space list pages
* Fix some chat related bugs
* Fix bug with joining spaces
# 1.7.1
* Fix pomade registration fallback in case of offline signer
# 1.7.0
* Enable email/password login
* Add up/edit to direct messages
* Fix a number of UI bugs
* Improve navigation on mobile
* Improve performance and syncing reliability
* Add proof of work to DMs
* Detect blossom support using supported_nips
* Improve notification badges
* Add voice rooms (@mplorentz)
* Re-design relay onboarding and settings
* Add android fallback for push notifications
* Fix file uploads on android
# 1.6.5
* Attempt to fix permission grant for notifications
* Make sync logic more robust
* Add unban/unallow support
* Improve support for downloading/opening protected images
* Add manual send/receive to wallet
* Show wallet status when wallet is unreachable
* Update nostr signer capacitor plugin
* Fix some safe area insets
* Update NIP 55 signer plugin (fixes Primal login)
* Refine space join dialogs and discover page
* Reopen the last DM that was open when navigating back to chat
* Get rid of ChatEnable interstitial
* Enable auth for relays we're publishing to
* Drag and drop space icons
* Add better muting support
* Add back button to settings menu
* Add page titles
* Improve scroll to event behavior
* Add in-memory search to rooms
* Fix editing messages with html tags
* Fix DM media detection
* Clean up reporting dialogs
* Improve room detail
# 1.6.4
* Clean up modal design
* Fix overflowing popovers
* Use space urls for relay hints
* Re-work notification badges
* Add push notification support via NIP 9a
* Optimistically load messaging relays to avoid unnecessary warning
* Recover from indexeddb not being available
* Fix safe area inset support
* Show space URL in top bar on mobile
* Fix calendar detail page
* Improve relay synchronization, especially for pyramid and relay29
* Improve invite code error handling
* Add wallet receive flow
* Fix safari image uploads
* Re-work recent activity page
* Add classified listing content type
* Use address for page param for replaceable events
* Refine discover page to avoid slowness
* Upgrade som dependencies
* Tag event author when tagging parent event
* Disable macos build
* Add room muting
# 1.6.3
* Fix scroll down button z index
* Hide tooltips on mobile
* Sort comments ascending
* Make video embeds rounded
* Fix ProfileMultiSelect styling
* Accept hex pubkeys/npubs/nprofiles in ProfileMultiSelect
* Tweak room edit form design
* Report pending signer to user
* Update default relays
* Fix chat list responsiveness
* Fix memory leak, notification badge not showing
* Improve space join flow
* Fix opening images in fullscreen dialog
* Add support for blocked relays
* Add authentication policy setting
* Add login with key if no signer is detected
* Publish default relay selections on signup
# 1.6.2
* Fix modal scrolling and style
# 1.6.1
* Fix skinny profile images
* Custom handler for relay urls
* Improve time based chat partitioning
* Improve authenticated image access interop
* Fix image detail dialog
* Fix zapper loading
* Fix recent events missing in feeds
# 1.6.0
* Switch back to indexeddb to fix memory and performance
* Add pay invoice functionality
* Add space membership management and bans
* Add event info to profile dialog
* Add better room membership management
* Refactor stores for performance
* Hide nav when keyboard is open
* Handle flotilla links in-app
* Fix new messages indicator z-index
* Fix some display bugs
* Add date to chat items
* Refine data synchronization
* Hide nav when keyboard is open on mobile
# 1.5.3
* Add space edit form
* Improve room syncing
* Return better blossom errors
* Fix access restricted bugs
* Add room detail dialog
* Fix broken link to self hosting
* Tweak shadows
* Always join spaces when visiting them
# 1.5.2
* Fix negentropy room syncing
# 1.5.1
* Fix chat path link
# 1.5.0
* Restyle mobile dialogs
* Add room membership lists
* Add space membership lists
* Add edit room form
* Support closed/private/restricted/hidden rooms
* Add hosting services page
* Improve performance and UI
* Fix push notifications
* Improve error detection and handling
* Support invite links on discover page
* Add link to landlubber if user is admin
* Clear reply/share/edit on escape
# 1.4.1
* Improve data synchronization
* Fix app url on capacitor deployments
# 1.4.0
* Allow "editing" chat messages
* Check for room create permission
* Re-work space navigation
* Show all messages in non-nip29 chat
* Improve synchronization logic
* Add connection status to space menu
* Add icon picker to room create component
* Improve mention suggestions
* Improve storage adapter and relay list performance
* Fix modals
* Add room deletion
* Fix zapper loading
* Add support for relay/group member lists and join/leave events
# 1.3.1
* Fix memory leak in storage adapter
* Show fewer annoying toast messages
# 1.3.0
* Add optional badge and sound for notifications
* Improve link rendering
* Remove imgproxy
* Bring back blossom feature detection for spaces
* Improve light theme
* Add more info to signer status
* Simplify navigation for adding a space
* Add ability to scan QR code for invite links
* Streamline wallet setup and move receive address setting
* Remove indexeddb on mobile, use capacitor file storage API
* Fix duplicate DMs showing up
# 1.2.5
* Fix icons in build
# 1.2.4
* Add direct message alerts
* Add alert settings page
* Add instructions to key download
* Add option that allows relays to strip signatures
* Detect relays that mostly refuse to serve requests
* Compress and upload profile images
* Use system theme by default
* Switch icon set, refactor how they're included
* Use capacitor's preferences for storage instead of localStorage
# 1.2.3
* Add `created_at` to event info dialog
* Add signer status to profile page
* Re-work bunker login flow
* Add in-app onboarding flow
* Only protect events if relay authenticates
* Filter out non-global chats from global chat
* Improve publish status indicator
* Fix encrypted upload content type
* Add relays to event details dialog
* Add universal link handler for apps
# 1.2.2
* Fix phantom chat notifications
* Fix zaps on mobile
# 1.2.1
* Add zaps to chat, threads, and events
* Add funding goals
* Add NWC support
* Add wallet settings page
* Handle invalid bunker url
* Fix sidebar overflow
* Fix profile npub display
# 1.2.0
* Fix sort order of thread comments
* Fix link display when no title is available
* Fix making profiles non-protected
* Replace bunker url with relay claims for notifier auth
* Add push notifications on all platforms
* Add "mark all as read" on desktop
* Re-design space dashboard
# 1.1.1
* Add chat quick link
# 1.1.0
* Add better theming support
* Improve forms for entering invite codes
* Rely more heavily on NIP 29 for rooms
* Support multiple platform relays
* Remove default general room
* Remove room tag from threads/calendars
* Show pubkey on profile detail
* Support pasting pubkey into chat start dialog
* Add minimal style for quoted messages
# 1.0.4
* Fix thunk status click handler
* Remove duplicate dependencies
* Improve navigation on white-labeled instances
* Add setting for font size
# 1.0.3
* Add light theme
* Use correct alerts server
* Ignore relay errors for claims
* Fix inline code blocks
* Add custom emoji parsing and display
# 1.0.2
* Fix add relay button
* Fix safe inset areas
* Better rendering for errors from relays
* Improve remote signer login
# 1.0.1
* Fix relay images in nav
* Fix relay nav overflow
# 1.0.0
* Add alerts via Anchor
* Fix nip46 signer connect
* Allow use of cleartext relays on native builds
* Fix some modal state bugs caused by svelte 5
* Detect blossom support on community relays
* Use user blossom server list in settings
* Fix some feed bugs
* Improve thunk indicator
* Update storage adapters
* Fix modal flash
* Switch to pnpm
* Improve calendar windowing
# 0.2.14
* Add calendar event editing
# 0.2.13
* Fix android keyboard issue
# 0.2.12
* Fix keyboard covering chat input
* Fix thread replies
* Make error reporting and analytics optional
* Replace long press with tap target
* Fix time input
* Fix nevent hints for url-specific stuff
* Fix confirm and reactions on mobile
* Add reply to chat on mobile
* Fix profile suggestions
# 0.2.11
* Add in-app signup flow on ios
* Add profile deletion
# 0.2.10
* Improve space discovery
# 0.2.9
* Add NIP 01 signup flow on mobile
# 0.2.8
* Show spinner when joining a room
* Reduce self-rate limiting of REQs
* Fix disabled signers link
* Prepare for iOS release
* Improve threads and calendar pages
* Improve quote rendering and new messages button
# 0.2.7
* Add calendar events
* Migrate to svelte 5 (fixes some bugs, probably introduces others)
* Migrate to new welshman editor
* Make reply indicator nicer
* Make share indicator nicer
* Improve feed loading
* Show marker for last activity in chat
# 0.2.6
* Add reply to long-press menu
* Fix @-mentions
* Replace nsec.app signup with njump.me
* Add new messages button in rooms
* Add media server settings
* Add build hash to about page
# 0.2.5
* Improve room and data loading
* Use @welshman/editor
* Drop support for legacy event kinds
* Add support for back button navigation on android
* Remove note to self page (still available via chat)
* Improve chat conversation search
* Change how reply UI works
# 0.2.4
* Update icons
# 0.2.3
* Add NIP 56 reports for messages and threads
* Add ToS and privacy policy
* Add avatar fallback icons
* Add mark as read to chats
* Add send button to chat compose
* Accommodate onion URLs
* Improve loading and notifications
# 0.2.2
* Fix bug with sending messages
# 0.2.1
* Improve performance, as well as scrolling and loading
+56
View File
@@ -0,0 +1,56 @@
## Project Overview
Flotilla is a Nostr "relays as groups" community chat client. It implements NIP-29 (relay-based groups) to create Discord-like spaces (servers) and rooms (channels).
Please visit our [issue tracker](https://gitea.coracle.social/coracle/flotilla/issues) to contribute. Any new issues should be opened without a milestone, label, or project and the project owners will triage them.
### Milestones
Milestones indicate how soon a given task should be tackled.
- [Current](https://gitea.coracle.social/coracle/flotilla/issues?type=all&state=open&milestone=1) issues are immediately actionable.
- [Next](https://gitea.coracle.social/coracle/flotilla/issues?type=all&state=open&milestone=2) means an issue is blocked.
- [Future](https://gitea.coracle.social/coracle/flotilla/issues?type=all&state=open&milestone=3) means we're deferring work until a later date.
### Labels
- [Design](https://gitea.coracle.social/coracle/flotilla/issues?type=all&state=open&labels=15) issues need design work before being implemented. This might take the form of a high-quality mockup, wireframes, user flows, or just a couple notes about where things go, depending on the nature of the task.
- [Dev](https://gitea.coracle.social/coracle/flotilla/issues?type=all&state=open&labels=16) issues are ready to be implemented. Most of the work will be related to architecting and writing code.
- [Easy](https://gitea.coracle.social/coracle/flotilla/issues?type=all&state=open&labels=14) issues have no dependencies, and are scoped quite narrowly.
- [Priority](https://gitea.coracle.social/coracle/flotilla/issues?type=all&state=open&labels=6) issues include bugs and urgent feature requests. These should get attention first if possible, although sometimes long-standing performance issues or subtle bugs might end up here for a while.
- [Ideas](https://gitea.coracle.social/coracle/flotilla/issues?type=all&state=open&labels=13) are for things that aren't scoped out yet, or which need protocol work before getting designed or implemented.
### Projects
Issues may or may not have a project. Projects are used to group issues thematically just for organization.
## Coding conventions
There are a few conventions that are helpful to know right out of the gate.
- Most nostr protocol functionality is implemented via the [welshman library](https://welshman.coracle.social/)
- Use Svelte 4 **stores** rather than runes for all state outside UI components
- Most global state flows through Welshman's `repository` (unidirectional)
- Query state using `deriveEventsMapped` or `deriveProfile` etc
- Events are published via `publishThunk`, which allows for optimistic UI updates during signing/pow generation.
- Components should have minimal props - e.g. instead of passing a whole `relay` through, pass its `url`.
- Use `AbortController` when possible instead of request ids
- Use `undefined` or optional properties instead of `null`
- Do not use `any`. If there are type errors related to `unknown`, they are likely because the upstream definition of the data is incorrect.
- Avoid using `as`, except where necessary. Instead, annotate function parameters, and ensure upstream values are typed correctly.
- When dynamically building classes, use `cx` from `classnames`.
- Do not define svelte event handlers inline, instead name them and put them in the script section of templates.
## Contributing Workflow
To contribute, do the following:
- Find or create an issue and assign yourself (comment instead if you're not able to self-assign)
- If the issue is a design task, attach or link out to any mockups/wireframes/flowcharts
- Once a design task is completed, a maintainer will remove the `design` label and add the `dev` label
- If the issue is a development task, fork the repository and create a branch prefixed by the issue number, e.g. `105-deep-links`
- Before requesting a review, be sure to review any agent-generated code, run the pre-commit hooks, and test the changes.
- Open a PR and request a review. A maintainer will get back to you with requested changes, or will merge the PR.
- Keep your PR up-to-date by rebasing frequently on `dev`. Avoid force-pushing to `dev`.
- PRs are rebased, squashed, and merged to keep commit history simple.
- An issue may have multiple PRs. Once complete, it can be closed.
+32
View File
@@ -0,0 +1,32 @@
# Stage 1: Build
# Uses .env from build context for config (logo, branding, etc.)
# Optional: docker build --build-arg VITE_BUILD_HASH=$(git rev-parse --short HEAD) -t flotilla .
FROM node:20-bookworm AS builder
RUN apt-get update && apt-get install -y --no-install-recommends curl
RUN npm install -g pnpm@latest
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN pnpm i
# Copy everything (including .env when present) - build.sh will source it
COPY . .
ARG VITE_BUILD_HASH
ENV VITE_BUILD_HASH=${VITE_BUILD_HASH}
ENV NODE_OPTIONS=--max_old_space_size=16384
RUN pnpm run build
FROM node:20-alpine
WORKDIR /app
# Copy only the built output - no source, no .env, no dev deps
COPY --from=builder /app/build ./build
CMD ["npx", "serve", "-s", "build"]
+22 -81
View File
@@ -2,106 +2,47 @@
A discord-like nostr client based on the idea of "relays as groups".
If you would like to be interoperable with Flotilla, please check out this draft NIP: https://github.com/coracle-social/nips/blob/relay-chat/xx.md
# Deploy
To run your own Flotilla, it's as simple as `npm run build`, then serve the `build` directory.
If you would like to be interoperable with Flotilla, please check out this guide: https://habla.news/u/hodlbod@coracle.social/1741286140797
## Environment
You can also optionally create an `.env.local` file and populate it with the following environment variables (see `.env` for examples):
You can also optionally create an `.env.local` file and populate it with the following environment variables (see `.env.template` for examples):
- `VITE_DEFAULT_PUBKEYS` - A comma-separated list of hex pubkeys for bootstrapping web of trust.
- `VITE_PLATFORM_URL` - The url where the app will be hosted. This is only used for build-time population of meta tags.
- `VITE_DEFAULT_PUBKEYS` - A comma-separated list of hex pubkeys for bootstrapping web of trust
- `VITE_PLATFORM_URL` - The url where the app will be hosted
- `VITE_PLATFORM_NAME` - The name of the app
- `VITE_PLATFORM_LOGO` - A logo url for the app
- `VITE_PLATFORM_RELAY` - A relay url that will make flotilla operate in "platform mode". Disables all space browse/add/select functionality and makes the platform relay the home page.
- `VITE_PLATFORM_LOGO` - A logo url for the app. Can be a local path or https link. Must be a PNG file.
- `VITE_PLATFORM_RELAYS` - A list of comma-separated relay urls that will make flotilla operate in "platform mode". Disables all space browse/add/select functionality and makes the first platform relay the home page.
- `VITE_PLATFORM_ACCENT` - A hex color for the app's accent color
- `VITE_PLATFORM_DESCRIPTION` - A description of the app
- `VITE_GLITCHTIP_API_KEY` - A Sentry DSN for use with glitchtip (error reporting)
- `GLITCHTIP_AUTH_TOKEN` - A glitchtip auth token for error reporting
These values **won't** be used for a built version. Instead, env variables should be provided to `build.sh` directly or to the built container.
If you're deploying a custom version of flotilla, be sure to remove the `plausible.coracle.social` script from `app.html`. This sends analytics to a server hosted by the developer.
## Nginx/TLS (optional)
## Development
If you'd like to set up flotilla on a server you control, you'll want to set up a reverse proxy and provision a TSL certificate for the domain you'll be using. You should also make sure to add swap to your server.
See [CONTRIBUTING.md](CONTRIBUTING.md).
There will be some parts of the following templates, for example `<SERVER NAME>`, which you'll need to fill in before running the code.
## Deployment
First, create an `A` record with your DNS provider pointing to the IP of your server. This will allow certbot to create your certificate later.
Next install `nginx`, `git`, and `certbot`. If you're on a debian- or ubuntu-based distro, run `sudo apt-get update && sudo apt-get install nginx git certbot python3-certbot-nginx`.
Now, create a new user where your code will be stored, clone the repository, fill in your `.env.local` file, and build the app.
To run your own Flotilla, it's as simple as:
```sh
# Replace with your password
PASSWORD=<YOUR PASSWORD HERE>
# Add the user and set a password
adduser flotilla
echo flotilla:$PASSWORD | chpasswd
# Login as flotilla
sudo su flotilla
# Go to flotilla's home directory
cd ~
# Install nvm, yarn, clone repos
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
# Update PATH
. ~/.bashrc
# Clone repository and install dependencies
git clone https://github.com/coracle-social/flotilla.git
cd ~/flotilla
nvm install
nvm use
npm i
# Optionally create and populate .env.local to suit your use case
# Build the app
NODE_OPTIONS=--max_old_space_size=16384 npm run build
# Exit back to root
exit
pnpm install
pnpm run build
npx serve -s build
```
Once you've exited back to root, you can set up nginx. Place the following in a file named after your domain in the `/etc/nginx/sites-available` directory, for example, `flotilla.example.com`. This should match the `A` record you registered above.
Or, if you prefer to use a container:
```conf
server {
listen 80;
server_name <SERVER NAME>;
root /home/flotilla/flotilla/build;
index index.html;
location / {
try_files $uri /index.html;
}
}
```sh
podman run -d -p 3000:3000 ghcr.io/coracle-social/flotilla:latest
```
Now you can run `certbot`, which will provision a TLS certificate for your domain and update your nginx configuration.
Alternatively, you can copy the build files into a directory of your choice and serve it yourself:
```sh
mkdir ./mount
podman run -v ./mount:/app/mount ghcr.io/coracle-social/flotilla:latest bash -c 'cp -r build/* mount'
```
certbot --nginx -d <SERVER NAME>
```
Now, enable the site and restart nginx. If you want to be careful, run `nginx -t` before restarting nginx.
```
ln -s /etc/nginx/sites-{available,enabled}/<SERVER NAME>
service nginx restart
```
Now, visit your domain. You should be all set up!
# Development
Run `npm run dev` to get a dev server, and `npm run check:watch` to watch for typescript errors. When you're ready to commit, run `npm run format && npm run lint` and fix any errors that come up.
+12 -7
View File
@@ -1,19 +1,20 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
android {
namespace "social.flotilla"
compileSdk rootProject.ext.compileSdkVersion
namespace = "social.flotilla"
compileSdk = rootProject.ext.compileSdkVersion
defaultConfig {
applicationId "social.flotilla"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "0.2.2"
minSdk rootProject.ext.minSdkVersion
targetSdk rootProject.ext.targetSdkVersion
versionCode 46
versionName "1.7.4"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
// Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
ignoreAssetsPattern = '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
}
}
buildTypes {
@@ -35,6 +36,10 @@ dependencies {
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"
implementation "androidx.work:work-runtime:2.10.3"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "com.squareup.okhttp3:okhttp:4.12.0"
implementation "fr.acinq.secp256k1:secp256k1-kmp-jni-android:0.22.0"
implementation project(':capacitor-android')
testImplementation "junit:junit:$junitVersion"
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
+13 -2
View File
@@ -2,13 +2,24 @@
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
sourceCompatibility JavaVersion.VERSION_21
targetCompatibility JavaVersion.VERSION_21
}
}
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
dependencies {
implementation project(':aparajita-capacitor-secure-storage')
implementation project(':capacitor-community-safe-area')
implementation project(':capacitor-app')
implementation project(':capacitor-clipboard')
implementation project(':capacitor-filesystem')
implementation project(':capacitor-keyboard')
implementation project(':capacitor-preferences')
implementation project(':capacitor-push-notifications')
implementation project(':capacitor-share')
implementation project(':capawesome-capacitor-android-dark-mode-support')
implementation project(':capawesome-capacitor-badge')
implementation project(':nostr-signer-capacitor-plugin')
}
+17 -2
View File
@@ -6,18 +6,27 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true">
<activity
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation|density"
android:name=".MainActivity"
android:label="@string/title_activity_main"
android:theme="@style/AppTheme.NoActionBarLaunch"
android:windowSoftInputMode="adjustResize"
android:launchMode="singleTask"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="app.flotilla.social" />
</intent-filter>
</activity>
<provider
@@ -32,4 +41,10 @@
<!-- Permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.any" android:required="false" />
</manifest>
@@ -1,5 +1,15 @@
package social.flotilla;
import android.os.Bundle;
import com.getcapacitor.BridgeActivity;
public class MainActivity extends BridgeActivity {}
import social.flotilla.notifications.AndroidPushFallbackPlugin;
public class MainActivity extends BridgeActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
registerPlugin(AndroidPushFallbackPlugin.class);
super.onCreate(savedInstanceState);
}
}
@@ -0,0 +1,101 @@
package social.flotilla.notifications
import android.content.Context
import android.content.SharedPreferences
import androidx.work.Constraints
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.ExistingWorkPolicy
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequest
import androidx.work.OutOfQuotaPolicy
import androidx.work.PeriodicWorkRequest
import androidx.work.WorkManager
import com.getcapacitor.JSObject
import com.getcapacitor.Plugin
import com.getcapacitor.PluginCall
import com.getcapacitor.PluginMethod
import com.getcapacitor.annotation.CapacitorPlugin
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import java.util.concurrent.TimeUnit
@CapacitorPlugin(name = "AndroidPushFallback")
class AndroidPushFallbackPlugin : Plugin() {
companion object {
const val PREFS_NAME = "CapacitorStorage"
const val KEY_STATE = "androidPushFallback.state"
const val UNIQUE_PERIODIC_WORK = "androidPushFallback.periodic"
const val UNIQUE_IMMEDIATE_WORK = "androidPushFallback.immediate"
}
private fun getPrefs(): SharedPreferences {
return context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
}
@PluginMethod
fun syncState(call: PluginCall) {
val state: JSObject? = call.getObject("state")
if (state != null) {
getPrefs().edit().putString(KEY_STATE, state.toString()).apply()
if (isEnabled(state.toString())) {
scheduleWork()
} else {
cancelWork()
}
}
call.resolve()
}
private fun isEnabled(rawState: String?): Boolean {
if (rawState == null || rawState.isEmpty()) {
return false
}
return try {
val state = JSONObject(rawState)
val subscriptions: JSONArray? = state.optJSONArray("subscriptions")
subscriptions != null && subscriptions.length() > 0
} catch (_: JSONException) {
false
}
}
private fun scheduleWork() {
val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
val workManager = WorkManager.getInstance(context)
val periodic = PeriodicWorkRequest.Builder(
AndroidPushFallbackWorker::class.java,
15,
TimeUnit.MINUTES,
).setConstraints(constraints).build()
val immediate = OneTimeWorkRequest.Builder(AndroidPushFallbackWorker::class.java)
.setConstraints(constraints)
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
.build()
workManager.enqueueUniquePeriodicWork(
UNIQUE_PERIODIC_WORK,
ExistingPeriodicWorkPolicy.UPDATE,
periodic,
)
workManager.enqueueUniqueWork(
UNIQUE_IMMEDIATE_WORK,
ExistingWorkPolicy.REPLACE,
immediate,
)
}
private fun cancelWork() {
val workManager = WorkManager.getInstance(context)
workManager.cancelUniqueWork(UNIQUE_IMMEDIATE_WORK)
workManager.cancelUniqueWork(UNIQUE_PERIODIC_WORK)
}
}
@@ -0,0 +1,861 @@
package social.flotilla.notifications
import android.Manifest
import android.app.NotificationChannel
import android.app.NotificationManager
import android.util.Log
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.app.ActivityManager
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.database.Cursor
import android.net.Uri
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import androidx.work.Worker
import androidx.work.WorkerParameters
import fr.acinq.secp256k1.Secp256k1
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import okhttp3.WebSocket
import okhttp3.WebSocketListener
import org.json.JSONArray
import org.json.JSONObject
import social.flotilla.notifications.AndroidPushFallbackPlugin.Companion.KEY_STATE
import social.flotilla.notifications.AndroidPushFallbackPlugin.Companion.PREFS_NAME
import java.nio.charset.StandardCharsets
import java.security.MessageDigest
import java.security.SecureRandom
import java.util.Arrays
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import android.util.Base64
class AndroidPushFallbackWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
companion object {
private const val TAG = "PushFallback"
private const val CHANNEL_ID = "flotilla_fallback"
private const val CURSOR_PREFIX = "androidPushFallback.cursor."
private const val SOCKET_TIMEOUT_SECONDS = 30L
private const val REJECTED = "__REJECTED__"
private const val KIND_RELAY_AUTH = 22242
private const val KIND_NIP46_RPC = 24133
private val SECP = Secp256k1.get()
}
private val prefs: SharedPreferences =
context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
private val client: OkHttpClient = OkHttpClient.Builder().build()
// ---- Socket pool ----
// Opens each relay URL at most once; caller must invoke closeAll() when done.
private inner class SocketPool {
private val sockets = ConcurrentHashMap<String, WebSocket>()
fun open(url: String, listener: WebSocketListener): WebSocket =
sockets.getOrPut(url) {
client.newWebSocket(Request.Builder().url(url).build(), listener)
}
fun closeAll() {
for ((_, ws) in sockets) ws.close(1000, "done")
sockets.clear()
}
}
override fun doWork(): Result {
Log.i(TAG, "doWork() started")
if (isAppInForeground()) {
return Result.success()
}
val pool = SocketPool()
try {
val rawState = prefs.getString(KEY_STATE, "") ?: ""
if (rawState.isEmpty()) return Result.success()
val state = JSONObject(rawState)
val sessionInfo = getSessionInfo(state)
val subscriptions = parseSubscriptions(state)
if (subscriptions.isEmpty()) return Result.success()
val activeSince = state.optLong("activeSince", 0L)
val seen = mutableSetOf<String>()
val newEvents = mutableListOf<Pair<String, JSONObject>>()
for (sub in subscriptions) {
val cursorKey = CURSOR_PREFIX + sub.relay + ":" + sub.key
val since = maxOf(prefs.getLong(cursorKey, 0L), activeSince)
val result = pollRelay(sub, since, sessionInfo, pool)
if (result.lastCursor > prefs.getLong(cursorKey, 0L)) {
prefs.edit().putLong(cursorKey, result.lastCursor).apply()
}
for (event in result.events) {
val id = event.optString("id", "")
if (id.isNotEmpty() && seen.add(id)) {
newEvents.add(Pair(sub.relay, event))
}
}
}
for ((relay, event) in newEvents) {
postNotification(relay, event)
}
return Result.success()
} catch (e: Exception) {
Log.e(TAG, "Worker failed", e)
return Result.retry()
} finally {
pool.closeAll()
client.dispatcher.executorService.shutdown()
}
}
private fun isAppInForeground(): Boolean {
val am = applicationContext.getSystemService(ActivityManager::class.java) ?: return false
val tasks = am.getRunningAppProcesses() ?: return false
val pkg = applicationContext.packageName
return tasks.any { it.processName == pkg && it.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND }
}
private fun getSessionInfo(state: JSONObject): SessionInfo {
val session = state.optJSONObject("session") ?: return SessionInfo("anonymous", "", JSONObject())
return SessionInfo(
session.optString("method", "anonymous"),
session.optString("pubkey", ""),
session,
)
}
private fun parseSubscriptions(state: JSONObject): List<Subscription> {
val result = mutableListOf<Subscription>()
val arr = state.optJSONArray("subscriptions") ?: return result
for (i in 0 until arr.length()) {
val item = arr.optJSONObject(i) ?: continue
val relay = item.optString("relay", "").trim()
if (!relay.startsWith("wss://") && !relay.startsWith("ws://")) continue
val filters = item.optJSONArray("filters")
if (filters == null || filters.length() == 0) continue
val key = item.optString("key", "").trim()
result.add(Subscription(relay, key, filters, item.optJSONArray("ignore")))
}
return result
}
private fun pollRelay(sub: Subscription, since: Long, sessionInfo: SessionInfo, pool: SocketPool): RelayResult {
val result = RelayResult()
val latch = CountDownLatch(1)
val listener = RelayListener(sub, since, sessionInfo, result, latch, pool)
pool.open(sub.relay, listener)
if (!latch.await(SOCKET_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
Log.d(TAG, "Relay ${sub.relay} timed out")
}
return result
}
private fun postNotification(relay: String, event: JSONObject) {
val context = applicationContext
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED
) return
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val manager = context.getSystemService(NotificationManager::class.java)
if (manager != null && manager.getNotificationChannel(CHANNEL_ID) == null) {
val channel = NotificationChannel(CHANNEL_ID, "Fallback Notifications", NotificationManager.IMPORTANCE_DEFAULT)
channel.description = "Notifications delivered by Android background fallback"
manager.createNotificationChannel(channel)
}
}
val id = event.optString("id", "")
val encodedRelay = Uri.encode(relay)
val url = "https://app.flotilla.social/?relay=$encodedRelay&id=$id"
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
intent.setPackage(context.packageName)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
val pendingIntent = PendingIntent.getActivity(
context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
val body = "New activity"
val notification = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(android.R.drawable.stat_notify_chat)
.setContentTitle("Flotilla")
.setContentText(body)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent)
.build()
val notificationId = id.hashCode().let { if (it == 0) 1 else it }
NotificationManagerCompat.from(context).notify(notificationId, notification)
}
private fun matchesFilter(filter: JSONObject, event: JSONObject): Boolean {
val kinds = filter.optJSONArray("kinds")
if (kinds != null && kinds.length() > 0) {
val kind = event.optInt("kind", -1)
var found = false
for (i in 0 until kinds.length()) {
if (kinds.optInt(i, -1) == kind) { found = true; break }
}
if (!found) return false
}
val tags = event.optJSONArray("tags")
val iter = filter.keys()
while (iter.hasNext()) {
val key = iter.next()
if (!key.startsWith("#")) continue
val tagName = key.substring(1)
val allowed = filter.optJSONArray(key) ?: continue
if (allowed.length() == 0) continue
val allowedValues = mutableSetOf<String>()
for (i in 0 until allowed.length()) {
val v = allowed.optString(i, "")
if (v.isNotEmpty()) allowedValues.add(v)
}
var matched = false
if (tags != null) {
for (i in 0 until tags.length()) {
val tag = tags.optJSONArray(i) ?: continue
if (tag.optString(0, "") == tagName && allowedValues.contains(tag.optString(1, ""))) {
matched = true; break
}
}
}
if (!matched) return false
}
return true
}
// ---- Crypto helpers ----
private fun computeEventId(event: JSONObject): String {
return try {
val serialized = JSONArray()
serialized.put(0)
serialized.put(event.optString("pubkey", ""))
serialized.put(event.optLong("created_at", 0))
serialized.put(event.optInt("kind", 0))
serialized.put(event.optJSONArray("tags") ?: JSONArray())
serialized.put(event.optString("content", ""))
// JSONObject escapes forward slashes (/ -> \/), but NIP-01 event ID hashing
// requires unescaped slashes. Replace them before hashing.
val serializedStr = serialized.toString().replace("\\/", "/")
bytesToHex(sha256(serializedStr.toByteArray(StandardCharsets.UTF_8)))
} catch (_: Exception) {
""
}
}
private fun deriveXOnlyPubkey(secretHex: String): String {
val secret = hexToBytes(secretHex)
if (secret.size != 32 || !SECP.secKeyVerify(secret)) return ""
val pubkey65 = try { SECP.pubkeyCreate(secret) } catch (_: Exception) { return "" }
if (pubkey65.size != 65) return ""
return bytesToHex(Arrays.copyOfRange(pubkey65, 1, 33))
}
private fun schnorrSign(secretHex: String, messageHex: String): String {
val sk = hexToBytes(secretHex)
val msg = hexToBytes(messageHex)
if (sk.size != 32 || msg.size != 32 || !SECP.secKeyVerify(sk)) return ""
val aux = ByteArray(32).also { SecureRandom().nextBytes(it) }
val sig = try { SECP.signSchnorr(msg, sk, aux) } catch (_: Exception) { return "" }
if (sig.size != 64) return ""
return bytesToHex(sig)
}
private fun sha256(input: ByteArray): ByteArray =
try { MessageDigest.getInstance("SHA-256").digest(input) } catch (_: Exception) { ByteArray(32) }
private fun hexToBytes(hex: String?): ByteArray {
var s = hex?.trim()?.lowercase() ?: ""
if (s.startsWith("0x")) s = s.substring(2)
if (s.length % 2 == 1) s = "0$s"
val bytes = ByteArray(s.length / 2)
var i = 0
while (i < s.length) {
val hi = Character.digit(s[i], 16)
val lo = Character.digit(s[i + 1], 16)
if (hi < 0 || lo < 0) return ByteArray(0)
bytes[i / 2] = ((hi shl 4) + lo).toByte()
i += 2
}
return bytes
}
private fun bytesToHex(bytes: ByteArray): String {
val hex = "0123456789abcdef".toCharArray()
val chars = CharArray(bytes.size * 2)
for (i in bytes.indices) {
val v = bytes[i].toInt() and 0xFF
chars[i * 2] = hex[v ushr 4]
chars[i * 2 + 1] = hex[v and 0x0F]
}
return String(chars)
}
// ---- NIP-44 encryption (v2: ECDH + HKDF + ChaCha20 + HMAC-SHA256) ----
private fun nip44ConversationKey(clientSecret: String, theirPubkey: String): ByteArray {
val sk = hexToBytes(clientSecret)
val pk = hexToBytes("02$theirPubkey")
if (sk.size != 32 || pk.size != 33) return ByteArray(0)
val shared = try { SECP.pubKeyTweakMul(pk, sk) } catch (_: Exception) { return ByteArray(0) }
if (shared.size != 65) return ByteArray(0)
val sharedX = Arrays.copyOfRange(shared, 1, 33)
return hkdfExtract(sharedX, "nip44-v2".toByteArray(StandardCharsets.UTF_8))
}
private fun hkdfExtract(ikm: ByteArray, salt: ByteArray): ByteArray {
val mac = javax.crypto.Mac.getInstance("HmacSHA256")
mac.init(javax.crypto.spec.SecretKeySpec(salt, "HmacSHA256"))
return mac.doFinal(ikm)
}
private fun hkdfExpand(prk: ByteArray, info: ByteArray, length: Int): ByteArray {
val mac = javax.crypto.Mac.getInstance("HmacSHA256")
val result = ByteArray(length)
var prev = ByteArray(0)
var offset = 0
var counter = 1
while (offset < length) {
mac.init(javax.crypto.spec.SecretKeySpec(prk, "HmacSHA256"))
mac.update(prev)
mac.update(info)
mac.update(counter.toByte())
prev = mac.doFinal()
val toCopy = minOf(prev.size, length - offset)
System.arraycopy(prev, 0, result, offset, toCopy)
offset += toCopy
counter++
}
return result
}
private fun hmacSha256(key: ByteArray, vararg parts: ByteArray): ByteArray {
val mac = javax.crypto.Mac.getInstance("HmacSHA256")
mac.init(javax.crypto.spec.SecretKeySpec(key, "HmacSHA256"))
for (part in parts) mac.update(part)
return mac.doFinal()
}
// ChaCha20 block function per RFC 8439
private fun chacha20Block(key: ByteArray, counter: Int, nonce: ByteArray): ByteArray {
fun Int.rotl(n: Int) = (this shl n) or (this ushr (32 - n))
val state = IntArray(16)
state[0] = 0x61707865; state[1] = 0x3320646e; state[2] = 0x79622d32; state[3] = 0x6b206574
for (i in 0..7) state[4 + i] = (key[i*4].toInt() and 0xFF) or
((key[i*4+1].toInt() and 0xFF) shl 8) or
((key[i*4+2].toInt() and 0xFF) shl 16) or
((key[i*4+3].toInt() and 0xFF) shl 24)
state[12] = counter
for (i in 0..2) state[13 + i] = (nonce[i*4].toInt() and 0xFF) or
((nonce[i*4+1].toInt() and 0xFF) shl 8) or
((nonce[i*4+2].toInt() and 0xFF) shl 16) or
((nonce[i*4+3].toInt() and 0xFF) shl 24)
val working = state.copyOf()
repeat(10) {
fun quarterRound(a: Int, b: Int, c: Int, d: Int) {
working[a] += working[b]; working[d] = (working[d] xor working[a]).rotl(16)
working[c] += working[d]; working[b] = (working[b] xor working[c]).rotl(12)
working[a] += working[b]; working[d] = (working[d] xor working[a]).rotl(8)
working[c] += working[d]; working[b] = (working[b] xor working[c]).rotl(7)
}
quarterRound(0,4,8,12); quarterRound(1,5,9,13); quarterRound(2,6,10,14); quarterRound(3,7,11,15)
quarterRound(0,5,10,15); quarterRound(1,6,11,12); quarterRound(2,7,8,13); quarterRound(3,4,9,14)
}
val out = ByteArray(64)
for (i in 0..15) {
val v = working[i] + state[i]
out[i*4] = v.toByte()
out[i*4+1] = (v ushr 8).toByte()
out[i*4+2] = (v ushr 16).toByte()
out[i*4+3] = (v ushr 24).toByte()
}
return out
}
private fun chacha20(key: ByteArray, nonce: ByteArray, data: ByteArray): ByteArray {
val out = ByteArray(data.size)
var counter = 0
var offset = 0
while (offset < data.size) {
val block = chacha20Block(key, counter, nonce)
val len = minOf(64, data.size - offset)
for (i in 0 until len) out[offset + i] = (data[offset + i].toInt() xor block[i].toInt()).toByte()
offset += len
counter++
}
return out
}
private fun nip44CalcPaddedLen(len: Int): Int {
if (len <= 32) return 32
val nextPower = 1 shl (Math.floor(Math.log((len - 1).toDouble()) / Math.log(2.0)).toInt() + 1)
val chunk = if (nextPower <= 256) 32 else nextPower / 8
return chunk * ((len - 1) / chunk + 1)
}
private fun nip44Pad(plaintext: String): ByteArray {
val unpadded = plaintext.toByteArray(StandardCharsets.UTF_8)
val len = unpadded.size
val padded = ByteArray(2 + nip44CalcPaddedLen(len))
padded[0] = (len ushr 8).toByte()
padded[1] = len.toByte()
System.arraycopy(unpadded, 0, padded, 2, len)
return padded
}
private fun nip44Unpad(padded: ByteArray): String {
val len = ((padded[0].toInt() and 0xFF) shl 8) or (padded[1].toInt() and 0xFF)
if (len == 0 || len > padded.size - 2) return ""
return String(padded, 2, len, StandardCharsets.UTF_8)
}
private fun encryptNip44(plaintext: String, conversationKey: ByteArray): String {
return try {
val nonce = ByteArray(32).also { SecureRandom().nextBytes(it) }
val keys = hkdfExpand(conversationKey, nonce, 76)
val chachaKey = keys.sliceArray(0 until 32)
val chachaNonce = keys.sliceArray(32 until 44)
val hmacKey = keys.sliceArray(44 until 76)
val padded = nip44Pad(plaintext)
val ciphertext = chacha20(chachaKey, chachaNonce, padded)
val mac = hmacSha256(hmacKey, nonce, ciphertext)
val payload = ByteArray(1 + 32 + ciphertext.size + 32)
payload[0] = 2
System.arraycopy(nonce, 0, payload, 1, 32)
System.arraycopy(ciphertext, 0, payload, 33, ciphertext.size)
System.arraycopy(mac, 0, payload, 33 + ciphertext.size, 32)
Base64.encodeToString(payload, Base64.NO_WRAP)
} catch (_: Exception) {
""
}
}
private fun decryptNip44(payload: String, conversationKey: ByteArray): String {
return try {
if (payload.isEmpty() || payload[0] == '#') return ""
val data = Base64.decode(payload, Base64.NO_WRAP)
if (data.size < 99 || data[0] != 2.toByte()) return ""
val nonce = data.sliceArray(1 until 33)
val ciphertext = data.sliceArray(33 until data.size - 32)
val mac = data.sliceArray(data.size - 32 until data.size)
val keys = hkdfExpand(conversationKey, nonce, 76)
val chachaKey = keys.sliceArray(0 until 32)
val chachaNonce = keys.sliceArray(32 until 44)
val hmacKey = keys.sliceArray(44 until 76)
val expectedMac = hmacSha256(hmacKey, nonce, ciphertext)
if (!expectedMac.contentEquals(mac)) return ""
val padded = chacha20(chachaKey, chachaNonce, ciphertext)
nip44Unpad(padded)
} catch (_: Exception) {
""
}
}
// ---- Signing ----
private fun signWithNip01Secret(secretHex: String, eventJson: String, expectedPubkey: String): String {
return try {
val secret = hexToBytes(secretHex)
if (secret.size != 32) return ""
val event = JSONObject(eventJson)
var pubkey = event.optString("pubkey", expectedPubkey)
if (pubkey.isEmpty()) pubkey = deriveXOnlyPubkey(secretHex)
if (pubkey.isEmpty()) return ""
event.put("pubkey", pubkey)
val id = computeEventId(event)
if (id.isEmpty()) return ""
val sig = schnorrSign(secretHex, id)
if (sig.isEmpty()) return ""
event.put("id", id)
event.put("sig", sig)
event.toString()
} catch (_: Exception) {
""
}
}
private fun signWithNip55ContentResolver(packageName: String, eventJson: String, pubkey: String): String {
val uri = Uri.parse("content://$packageName.SIGN_EVENT")
var cursor: Cursor? = null
return try {
cursor = applicationContext.contentResolver.query(uri, arrayOf(eventJson, "", pubkey), "1", null, null)
if (cursor == null || !cursor.moveToFirst()) return ""
val rejIdx = cursor.getColumnIndex("rejected")
if (rejIdx >= 0) {
val v = cursor.getString(rejIdx)
if (v == "1" || v.equals("true", ignoreCase = true)) return REJECTED
}
val eventIdx = cursor.getColumnIndex("event")
if (eventIdx >= 0) cursor.getString(eventIdx) ?: "" else ""
} catch (_: Exception) {
""
} finally {
cursor?.close()
}
}
// ---- Data types ----
private data class SessionInfo(
val method: String,
val pubkey: String,
val session: JSONObject,
)
private data class Subscription(
val relay: String,
val key: String,
val filters: JSONArray,
val ignore: JSONArray?,
)
private class RelayResult {
val events = mutableListOf<JSONObject>()
var lastCursor = 0L
}
// ---- Relay listener ----
private inner class RelayListener(
private val sub: Subscription,
private val since: Long,
private val sessionInfo: SessionInfo,
private val result: RelayResult,
private val latch: CountDownLatch,
private val pool: SocketPool,
) : WebSocketListener() {
private val subId = UUID.randomUUID().toString().replace("-", "")
private var done = false
private var authed = false
private var authEventId = ""
private var nip46InFlight = false
private var pendingDone = false
override fun onOpen(webSocket: WebSocket, response: Response) {
sendReq(webSocket)
}
private fun sendReq(webSocket: WebSocket) {
val req = JSONArray()
req.put("REQ")
req.put(subId)
for (i in 0 until sub.filters.length()) {
val filter = sub.filters.optJSONObject(i) ?: continue
val shaped = JSONObject(filter.toString())
if (since > 0) shaped.put("since", since + 1)
shaped.put("limit", 1)
req.put(shaped)
}
if (req.length() <= 2) { finish(); return }
send(webSocket, req.toString())
}
override fun onMessage(webSocket: WebSocket, text: String) {
try {
val message = JSONArray(text)
Log.d(TAG, "Received message from ${sub.relay}: $text")
when (message.optString(0, "")) {
"EVENT" -> {
val event = message.optJSONObject(2) ?: return
if (!matchesAnyFilter(sub.filters, event)) return
if (isIgnored(event)) return
result.events.add(event)
val createdAt = event.optLong("created_at", 0L)
if (createdAt > result.lastCursor) result.lastCursor = createdAt
}
"AUTH" -> {
// Only auth once per connection
if (!authed) {
authed = true
tryAuth(webSocket, message.optString(1, ""))
}
}
"OK" -> {
val okId = message.optString(1, "")
val accepted = message.optBoolean(2, false)
if (accepted && okId == authEventId) sendReq(webSocket)
}
"EOSE" -> {
send(webSocket, JSONArray().apply { put("CLOSE"); put(subId) }.toString())
finish()
}
}
} catch (_: Exception) {
finish()
}
}
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) = finish()
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) = finish()
private fun finish() {
if (done) return
if (nip46InFlight) { pendingDone = true; return }
done = true
latch.countDown()
}
private fun isIgnored(event: JSONObject): Boolean {
val ignore = sub.ignore ?: return false
for (i in 0 until ignore.length()) {
val filter = ignore.optJSONObject(i) ?: continue
if (matchesFilter(filter, event)) return true
}
return false
}
private fun matchesAnyFilter(filters: JSONArray, event: JSONObject): Boolean {
for (i in 0 until filters.length()) {
val filter = filters.optJSONObject(i) ?: continue
if (matchesFilter(filter, event)) return true
}
return false
}
// ---- NIP-42 auth ----
private fun tryAuth(webSocket: WebSocket, challenge: String) {
if (challenge.isEmpty()) return
when (sessionInfo.method) {
"nip01" -> tryNip01Auth(webSocket, challenge)
"nip55" -> tryNip55Auth(webSocket, challenge)
"nip46" -> tryNip46Auth(webSocket, challenge)
// Pomade background auth is not supported: properly delegating to the Pomade signer
// from a background worker is complex, usage is rare, and relays that require auth
// may still be readable without it.
}
}
private fun buildAuthEvent(challenge: String): JSONObject {
return JSONObject().apply {
put("kind", KIND_RELAY_AUTH)
put("pubkey", sessionInfo.pubkey)
put("created_at", System.currentTimeMillis() / 1000L)
put("content", "")
put("id", "")
put("sig", "")
put("tags", JSONArray().apply {
put(JSONArray().apply { put("relay"); put(sub.relay) })
put(JSONArray().apply { put("challenge"); put(challenge) })
})
}
}
private fun sendAuthMessage(webSocket: WebSocket, signedEventJson: String): Boolean {
if (signedEventJson.isEmpty() || signedEventJson == REJECTED) return false
return try {
val event = JSONObject(signedEventJson)
authEventId = event.optString("id", "")
send(webSocket, JSONArray().apply { put("AUTH"); put(event) }.toString())
} catch (_: Exception) {
false
}
}
private fun send(webSocket: WebSocket, message: String): Boolean {
Log.d(TAG, "Sending message to ${webSocket.request().url}: $message")
return webSocket.send(message)
}
private fun tryNip01Auth(webSocket: WebSocket, challenge: String): Boolean {
val secret = sessionInfo.session.optString("secret", "")
if (secret.isEmpty()) return false
val signed = signWithNip01Secret(secret, buildAuthEvent(challenge).toString(), sessionInfo.pubkey)
return sendAuthMessage(webSocket, signed)
}
private fun tryNip55Auth(webSocket: WebSocket, challenge: String): Boolean {
val signerPackage = sessionInfo.session.optString("signer", "")
if (signerPackage.isEmpty()) return false
val signed = signWithNip55ContentResolver(signerPackage, buildAuthEvent(challenge).toString(), sessionInfo.pubkey)
return sendAuthMessage(webSocket, signed)
}
private fun tryNip46Auth(webSocket: WebSocket, challenge: String): Boolean {
val handler = sessionInfo.session.optJSONObject("handler") ?: return false
val clientSecret = sessionInfo.session.optString("secret", "")
val signerPubkey = handler.optString("pubkey", "")
val relays = handler.optJSONArray("relays")
if (clientSecret.isEmpty() || signerPubkey.isEmpty() || relays == null || relays.length() == 0) return false
val clientPubkey = deriveXOnlyPubkey(clientSecret)
if (clientPubkey.isEmpty()) return false
val authEventJson = buildAuthEvent(challenge).toString()
nip46InFlight = true
var success = false
try {
for (i in 0 until relays.length()) {
val signerRelay = relays.optString(i, "").trim()
if (!signerRelay.startsWith("wss://") && !signerRelay.startsWith("ws://")) continue
if (tryNip46ViaRelay(webSocket, signerRelay, clientSecret, clientPubkey, signerPubkey, authEventJson)) { success = true; break }
}
} finally {
nip46InFlight = false
if (pendingDone) finish()
}
return success
}
private fun tryNip46ViaRelay(
relaySocket: WebSocket,
signerRelay: String,
clientSecret: String,
clientPubkey: String,
signerPubkey: String,
authEventJson: String,
): Boolean {
val localLatch = CountDownLatch(1)
val signedEvent = StringBuilder()
val requestId = UUID.randomUUID().toString().replace("-", "")
val signerSocket = pool.open(signerRelay, object : WebSocketListener() {
private var done = false
override fun onOpen(webSocket: WebSocket, response: Response) {
try {
val rpcEnvelope = JSONObject().apply {
put("kind", KIND_NIP46_RPC)
put("pubkey", clientPubkey)
put("created_at", System.currentTimeMillis() / 1000L)
put("content", encryptNip44(
JSONObject().apply {
put("id", requestId)
put("method", "sign_event")
put("params", JSONArray().apply { put(authEventJson) })
}.toString(),
nip44ConversationKey(clientSecret, signerPubkey),
))
put("id", "")
put("sig", "")
put("tags", JSONArray().apply { put(JSONArray().apply { put("p"); put(signerPubkey) }) })
}
val signedEnvelope = signWithNip01Secret(clientSecret, rpcEnvelope.toString(), clientPubkey)
if (signedEnvelope.isEmpty()) { finish(); return }
val sentAt = System.currentTimeMillis() / 1000L
send(webSocket, JSONArray().apply { put("EVENT"); put(JSONObject(signedEnvelope)) }.toString())
send(webSocket, JSONArray().apply {
put("REQ")
put(requestId)
put(JSONObject().apply {
put("#p", JSONArray().apply { put(clientPubkey) })
put("kinds", JSONArray().apply { put(KIND_NIP46_RPC) })
put("since", sentAt)
put("limit", 10)
})
}.toString())
} catch (_: Exception) {
finish()
}
}
override fun onMessage(webSocket: WebSocket, text: String) {
try {
val message = JSONArray(text)
val msgType = message.optString(0, "")
Log.d(TAG, "NIP-46 signer message: $msgType from ${webSocket.request().url}")
if (msgType != "EVENT") return
val event = message.optJSONObject(2) ?: return
val tags = event.optJSONArray("tags")
var hasP = false
if (tags != null) {
for (i in 0 until tags.length()) {
val tag = tags.optJSONArray(i) ?: continue
if (tag.optString(0, "") == "p" && tag.optString(1, "") == clientPubkey) { hasP = true; break }
}
}
if (!hasP) { Log.d(TAG, "NIP-46 event missing p tag for client"); return }
val decryptedContent = decryptNip44(event.optString("content", ""), nip44ConversationKey(clientSecret, signerPubkey))
Log.d(TAG, "NIP-46 decrypted response: $decryptedContent")
if (decryptedContent.isEmpty()) return
val payload = JSONObject(decryptedContent)
if (requestId == payload.optString("id", "")) {
val result = payload.optString("result", "")
if (result.isNotEmpty()) {
signedEvent.setLength(0)
signedEvent.append(result)
finish()
}
}
} catch (e: Exception) {
Log.e(TAG, "NIP-46 signer message error", e)
}
}
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) = finish()
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) = finish()
private fun finish() {
if (!done) { done = true; localLatch.countDown() }
}
})
try {
localLatch.await(5, TimeUnit.SECONDS)
} catch (_: InterruptedException) {
return false
}
if (signedEvent.isEmpty()) return false
val authEvent = JSONObject(signedEvent.toString())
authEventId = authEvent.optString("id", "")
val authMessage = JSONArray().apply { put("AUTH"); put(authEvent) }.toString()
Log.d(TAG, "NIP-46 sending AUTH to relay ${relaySocket.request().url}: $authMessage")
return try {
relaySocket.send(authMessage)
} catch (e: Exception) {
Log.e(TAG, "NIP-46 failed to send AUTH", e)
false
}
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 531 B

After

Width:  |  Height:  |  Size: 899 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 916 B

After

Width:  |  Height:  |  Size: 711 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 277 B

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 350 B

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 697 B

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

+3 -4
View File
@@ -1,9 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
@@ -13,10 +11,11 @@
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:background">@null</item>
<item name="android:windowOptOutEdgeToEdgeEnforcement" tools:ignore="NewApi">true</item>
</style>
<style name="AppTheme.NoActionBarLaunch" parent="Theme.SplashScreen">
<item name="android:background">@drawable/splash</item>
</style>
</resources>
</resources>
+4 -2
View File
@@ -1,14 +1,16 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '2.2.20'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.2.1'
classpath 'com.google.gms:google-services:4.4.0'
classpath 'com.android.tools.build:gradle:8.13.2'
classpath 'com.google.gms:google-services:4.4.4'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
+35 -2
View File
@@ -1,6 +1,39 @@
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
include ':capacitor-android'
project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
project(':capacitor-android').projectDir = new File('../node_modules/.pnpm/@capacitor+android@8.0.1_@capacitor+core@8.0.1/node_modules/@capacitor/android/capacitor')
include ':aparajita-capacitor-secure-storage'
project(':aparajita-capacitor-secure-storage').projectDir = new File('../node_modules/.pnpm/@aparajita+capacitor-secure-storage@8.0.0/node_modules/@aparajita/capacitor-secure-storage/android')
include ':capacitor-community-safe-area'
project(':capacitor-community-safe-area').projectDir = new File('../node_modules/.pnpm/@capacitor-community+safe-area@8.0.1_@capacitor+core@8.0.1/node_modules/@capacitor-community/safe-area/android')
include ':capacitor-app'
project(':capacitor-app').projectDir = new File('../node_modules/.pnpm/@capacitor+app@8.0.0_@capacitor+core@8.0.1/node_modules/@capacitor/app/android')
include ':capacitor-clipboard'
project(':capacitor-clipboard').projectDir = new File('../node_modules/.pnpm/@capacitor+clipboard@8.0.1_@capacitor+core@8.0.1/node_modules/@capacitor/clipboard/android')
include ':capacitor-filesystem'
project(':capacitor-filesystem').projectDir = new File('../node_modules/.pnpm/@capacitor+filesystem@8.1.0_@capacitor+core@8.0.1/node_modules/@capacitor/filesystem/android')
include ':capacitor-keyboard'
project(':capacitor-keyboard').projectDir = new File('../node_modules/.pnpm/@capacitor+keyboard@8.0.0_@capacitor+core@8.0.1/node_modules/@capacitor/keyboard/android')
include ':capacitor-preferences'
project(':capacitor-preferences').projectDir = new File('../node_modules/.pnpm/@capacitor+preferences@8.0.0_@capacitor+core@8.0.1/node_modules/@capacitor/preferences/android')
include ':capacitor-push-notifications'
project(':capacitor-push-notifications').projectDir = new File('../node_modules/.pnpm/@capacitor+push-notifications@8.0.0_@capacitor+core@8.0.1/node_modules/@capacitor/push-notifications/android')
include ':capacitor-share'
project(':capacitor-share').projectDir = new File('../node_modules/.pnpm/@capacitor+share@8.0.1_@capacitor+core@8.0.1/node_modules/@capacitor/share/android')
include ':capawesome-capacitor-android-dark-mode-support'
project(':capawesome-capacitor-android-dark-mode-support').projectDir = new File('../node_modules/.pnpm/@capawesome+capacitor-android-dark-mode-support@8.0.0_@capacitor+core@8.0.1/node_modules/@capawesome/capacitor-android-dark-mode-support/android')
include ':capawesome-capacitor-badge'
project(':capawesome-capacitor-badge').projectDir = new File('../node_modules/.pnpm/@capawesome+capacitor-badge@8.0.0_@capacitor+core@8.0.1/node_modules/@capawesome/capacitor-badge/android')
include ':nostr-signer-capacitor-plugin'
project(':nostr-signer-capacitor-plugin').projectDir = new File('../node_modules/nostr-signer-capacitor-plugin/android')
project(':nostr-signer-capacitor-plugin').projectDir = new File('../node_modules/.pnpm/nostr-signer-capacitor-plugin@https+++codeload.github.com+coracle-social+nostr-signer-c_2704ecccfd05fcfb1ad8852744422b7c/node_modules/nostr-signer-capacitor-plugin/android')
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
+14 -11
View File
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -83,7 +85,8 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -111,7 +114,7 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
@@ -144,7 +147,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
@@ -152,7 +155,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -201,16 +204,16 @@ fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
+14 -12
View File
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@@ -57,22 +59,22 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
set CLASSPATH=
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
+16 -14
View File
@@ -1,16 +1,18 @@
ext {
minSdkVersion = 22
compileSdkVersion = 34
targetSdkVersion = 34
androidxActivityVersion = '1.8.0'
androidxAppCompatVersion = '1.6.1'
androidxCoordinatorLayoutVersion = '1.2.0'
androidxCoreVersion = '1.12.0'
androidxFragmentVersion = '1.6.2'
coreSplashScreenVersion = '1.0.1'
androidxWebkitVersion = '1.9.0'
minSdkVersion = 24
compileSdkVersion = 36
targetSdkVersion = 36
androidxActivityVersion = '1.11.0'
//https://github.com/ionic-team/capacitor/issues/7866
// androidxAppCompatVersion = '1.7.1'
androidxAppCompatVersion = '1.7.1'
androidxCoordinatorLayoutVersion = '1.3.0'
androidxCoreVersion = '1.17.0'
androidxFragmentVersion = '1.8.9'
coreSplashScreenVersion = '1.2.0'
androidxWebkitVersion = '1.14.0'
junitVersion = '4.13.2'
androidxJunitVersion = '1.1.5'
androidxEspressoCoreVersion = '3.5.1'
cordovaAndroidVersion = '10.1.1'
}
androidxJunitVersion = '1.3.0'
androidxEspressoCoreVersion = '3.7.0'
cordovaAndroidVersion = '14.0.1'
}
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -e
# Fetch tags and set to env vars
git fetch --prune --unshallow --tags || true
git describe --tags --abbrev=0 || true
export VITE_BUILD_VERSION=$RENDER_GIT_COMMIT
export VITE_BUILD_HASH=$RENDER_GIT_COMMIT
# Install dependencies
CI=0 pnpm i
# Rebuild sharp
pnpm rebuild
# The build runs out of memory at times
NODE_OPTIONS=--max_old_space_size=16384 pnpm run build
+15 -8
View File
@@ -6,21 +6,21 @@ if [ -f .env ]; then
source .env
fi
if [ -f .env.local ]; then
source .env.local
fi
# Avoid overwriting env vars provided directly
# https://stackoverflow.com/a/69127685/1467342
eval "$temp_env"
if [[ $VITE_PLATFORM_LOGO =~ ^https://* ]]; then
curl $VITE_PLATFORM_LOGO > static/logo.png
cp static/logo.png assets/logo.png
if [[ -z $VITE_BUILD_HASH ]]; then
export VITE_BUILD_HASH=$(git rev-parse --short HEAD)
fi
if [[ $VITE_PLATFORM_LOGO =~ ^https:// ]]; then
curl -fSL "$VITE_PLATFORM_LOGO" -o static/logo.png
export VITE_PLATFORM_LOGO=static/logo.png
fi
npx pwa-assets-generator
# Ensure generator uses local path (dotenv may have loaded URL from .env)
VITE_PLATFORM_LOGO="${VITE_PLATFORM_LOGO}" npx pwa-assets-generator
npx vite build
# Replace index.html variables with stuff from our env
@@ -28,3 +28,10 @@ perl -i -pe"s|{DESCRIPTION}|$VITE_PLATFORM_DESCRIPTION|g" build/index.html
perl -i -pe"s|{ACCENT}|$VITE_PLATFORM_ACCENT|g" build/index.html
perl -i -pe"s|{NAME}|$VITE_PLATFORM_NAME|g" build/index.html
perl -i -pe"s|{URL}|$VITE_PLATFORM_URL|g" build/index.html
npx cap sync
npx @capacitor/assets generate \
--iconBackgroundColor '#eeeeee' \
--iconBackgroundColorDark '#222222' \
--splashBackgroundColor '#ffffff' \
--splashBackgroundColorDark '#191E24'
+34 -9
View File
@@ -1,14 +1,39 @@
import type { CapacitorConfig } from '@capacitor/cli';
import type {CapacitorConfig} from "@capacitor/cli"
const config: CapacitorConfig = {
appId: 'social.flotilla',
appName: 'Flotilla',
webDir: 'build'
appId: "social.flotilla",
appName: "Flotilla",
webDir: "build",
ios: {
scheme: "Flotilla Chat",
},
android: {
adjustMarginsForEdgeToEdge: true,
},
plugins: {
CapacitorHttp: {
enabled: true,
},
SystemBars: {
insetsHandling: "enable",
},
SplashScreen: {
androidSplashResourceName: "splash"
}
}
};
androidSplashResourceName: "splash",
},
Keyboard: {
style: "DARK",
resizeOnFullScreen: true,
},
Badge: {
persist: true,
autoClear: true,
},
},
server: {
// Use this for live reload https://capacitorjs.com/docs/guides/live-reload
// url: "http://192.168.1.17:1847",
// cleartext: true,
},
}
export default config;
export default config
+13
View File
@@ -0,0 +1,13 @@
App/build
App/Pods
App/output
App/App/public
DerivedData
xcuserdata
# Cordova plugins for Capacitor
capacitor-cordova-ios-plugins
# Generated Config files
App/App/capacitor.config.json
App/App/config.xml
+430
View File
@@ -0,0 +1,430 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 48;
objects = {
/* Begin PBXBuildFile section */
2FAD9763203C412B000D30F8 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = 2FAD9762203C412B000D30F8 /* config.xml */; };
3478F0332E846FEB002431E0 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 3478F0322E846FEB002431E0 /* PrivacyInfo.xcprivacy */; };
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */ = {isa = PBXBuildFile; fileRef = 50379B222058CBB4000EE86E /* capacitor.config.json */; };
504EC3081FED79650016851F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504EC3071FED79650016851F /* AppDelegate.swift */; };
504EC30D1FED79650016851F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30B1FED79650016851F /* Main.storyboard */; };
504EC30F1FED79650016851F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30E1FED79650016851F /* Assets.xcassets */; };
504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC3101FED79650016851F /* LaunchScreen.storyboard */; };
50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; };
AC8D5382B9575A9124613C5D /* Pods_Flotilla_Chat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA42C7E3CF3FFF7A17A3A729 /* Pods_Flotilla_Chat.framework */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
051414282E0CC28400BE0BC8 /* Flotilla Chat.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Flotilla Chat.entitlements"; sourceTree = "<group>"; };
1F53EE54954731A2328CBC4B /* Pods-Flotilla Chat.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Flotilla Chat.release.xcconfig"; path = "Pods/Target Support Files/Pods-Flotilla Chat/Pods-Flotilla Chat.release.xcconfig"; sourceTree = "<group>"; };
2FAD9762203C412B000D30F8 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = config.xml; sourceTree = "<group>"; };
3478F0322E846FEB002431E0 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
50379B222058CBB4000EE86E /* capacitor.config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = capacitor.config.json; sourceTree = "<group>"; };
504EC3041FED79650016851F /* Flotilla Chat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Flotilla Chat.app"; sourceTree = BUILT_PRODUCTS_DIR; };
504EC3071FED79650016851F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
504EC30C1FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
504EC30E1FED79650016851F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
504EC3111FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
504EC3131FED79650016851F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
50B271D01FEDC1A000F3C39B /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = "<group>"; };
7B9FA71C362B734D9F965709 /* Pods-Flotilla Chat.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Flotilla Chat.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Flotilla Chat/Pods-Flotilla Chat.debug.xcconfig"; sourceTree = "<group>"; };
AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.release.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.release.xcconfig"; sourceTree = "<group>"; };
DA42C7E3CF3FFF7A17A3A729 /* Pods_Flotilla_Chat.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Flotilla_Chat.framework; sourceTree = BUILT_PRODUCTS_DIR; };
FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.debug.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
504EC3011FED79650016851F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
AC8D5382B9575A9124613C5D /* Pods_Flotilla_Chat.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
27E2DDA53C4D2A4D1A88CE4A /* Frameworks */ = {
isa = PBXGroup;
children = (
DA42C7E3CF3FFF7A17A3A729 /* Pods_Flotilla_Chat.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
504EC2FB1FED79650016851F = {
isa = PBXGroup;
children = (
3478F0322E846FEB002431E0 /* PrivacyInfo.xcprivacy */,
051414282E0CC28400BE0BC8 /* Flotilla Chat.entitlements */,
504EC3061FED79650016851F /* App */,
504EC3051FED79650016851F /* Products */,
7F8756D8B27F46E3366F6CEA /* Pods */,
27E2DDA53C4D2A4D1A88CE4A /* Frameworks */,
);
sourceTree = "<group>";
};
504EC3051FED79650016851F /* Products */ = {
isa = PBXGroup;
children = (
504EC3041FED79650016851F /* Flotilla Chat.app */,
);
name = Products;
sourceTree = "<group>";
};
504EC3061FED79650016851F /* App */ = {
isa = PBXGroup;
children = (
50379B222058CBB4000EE86E /* capacitor.config.json */,
504EC3071FED79650016851F /* AppDelegate.swift */,
504EC30B1FED79650016851F /* Main.storyboard */,
504EC30E1FED79650016851F /* Assets.xcassets */,
504EC3101FED79650016851F /* LaunchScreen.storyboard */,
504EC3131FED79650016851F /* Info.plist */,
2FAD9762203C412B000D30F8 /* config.xml */,
50B271D01FEDC1A000F3C39B /* public */,
);
path = App;
sourceTree = "<group>";
};
7F8756D8B27F46E3366F6CEA /* Pods */ = {
isa = PBXGroup;
children = (
FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */,
AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */,
7B9FA71C362B734D9F965709 /* Pods-Flotilla Chat.debug.xcconfig */,
1F53EE54954731A2328CBC4B /* Pods-Flotilla Chat.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
504EC3031FED79650016851F /* Flotilla Chat */ = {
isa = PBXNativeTarget;
buildConfigurationList = 504EC3161FED79650016851F /* Build configuration list for PBXNativeTarget "Flotilla Chat" */;
buildPhases = (
6634F4EFEBD30273BCE97C65 /* [CP] Check Pods Manifest.lock */,
504EC3001FED79650016851F /* Sources */,
504EC3011FED79650016851F /* Frameworks */,
504EC3021FED79650016851F /* Resources */,
9592DBEFFC6D2A0C8D5DEB22 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = "Flotilla Chat";
productName = App;
productReference = 504EC3041FED79650016851F /* Flotilla Chat.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
504EC2FC1FED79650016851F /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 920;
LastUpgradeCheck = 920;
TargetAttributes = {
504EC3031FED79650016851F = {
CreatedOnToolsVersion = 9.2;
LastSwiftMigration = 1100;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */;
compatibilityVersion = "Xcode 8.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 504EC2FB1FED79650016851F;
productRefGroup = 504EC3051FED79650016851F /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
504EC3031FED79650016851F /* Flotilla Chat */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
504EC3021FED79650016851F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */,
3478F0332E846FEB002431E0 /* PrivacyInfo.xcprivacy in Resources */,
50B271D11FEDC1A000F3C39B /* public in Resources */,
504EC30F1FED79650016851F /* Assets.xcassets in Resources */,
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */,
504EC30D1FED79650016851F /* Main.storyboard in Resources */,
2FAD9763203C412B000D30F8 /* config.xml in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
6634F4EFEBD30273BCE97C65 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Flotilla Chat-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
9592DBEFFC6D2A0C8D5DEB22 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Flotilla Chat/Pods-Flotilla Chat-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
504EC3001FED79650016851F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
504EC3081FED79650016851F /* AppDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
504EC30B1FED79650016851F /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
504EC30C1FED79650016851F /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
504EC3101FED79650016851F /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
504EC3111FED79650016851F /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
504EC3141FED79650016851F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
504EC3151FED79650016851F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
504EC3171FED79650016851F /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7B9FA71C362B734D9F965709 /* Pods-Flotilla Chat.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = "Flotilla Chat.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 37;
DEVELOPMENT_TEAM = S26U9DYW3A;
INFOPLIST_FILE = App/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Flotilla Chat";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.7.4;
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
PRODUCT_BUNDLE_IDENTIFIER = social.flotilla;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
504EC3181FED79650016851F /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 1F53EE54954731A2328CBC4B /* Pods-Flotilla Chat.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = "Flotilla Chat.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 37;
DEVELOPMENT_TEAM = S26U9DYW3A;
INFOPLIST_FILE = App/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Flotilla Chat";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.7.4;
PRODUCT_BUNDLE_IDENTIFIER = social.flotilla;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */ = {
isa = XCConfigurationList;
buildConfigurations = (
504EC3141FED79650016851F /* Debug */,
504EC3151FED79650016851F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
504EC3161FED79650016851F /* Build configuration list for PBXNativeTarget "Flotilla Chat" */ = {
isa = XCConfigurationList;
buildConfigurations = (
504EC3171FED79650016851F /* Debug */,
504EC3181FED79650016851F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 504EC2FC1FED79650016851F /* Project object */;
}
+58
View File
@@ -0,0 +1,58 @@
import UIKit
import Capacitor
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
// Called when the app was launched with a url. Feel free to add additional processing here,
// but if you want the App API to support tracking app url opens, make sure to keep this call
return ApplicationDelegateProxy.shared.application(app, open: url, options: options)
}
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
// Called when the app was launched with an activity, including Universal Links.
// Feel free to add additional processing here, but if you want the App API to support
// tracking app url opens, make sure to keep this call
return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler)
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// Enable push notifications https://capacitorjs.com/docs/apis/push-notifications
NotificationCenter.default.post(name: .capacitorDidRegisterForRemoteNotifications, object: deviceToken)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
// Enable push notifications https://capacitorjs.com/docs/apis/push-notifications
NotificationCenter.default.post(name: .capacitorDidFailToRegisterForRemoteNotifications, object: error)
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

@@ -0,0 +1,14 @@
{
"images": [
{
"idiom": "universal",
"size": "1024x1024",
"filename": "AppIcon-512@2x.png",
"platform": "ios"
}
],
"info": {
"author": "xcode",
"version": 1
}
}
@@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -0,0 +1,56 @@
{
"images": [
{
"idiom": "universal",
"filename": "Default@1x~universal~anyany.png",
"scale": "1x"
},
{
"idiom": "universal",
"filename": "Default@2x~universal~anyany.png",
"scale": "2x"
},
{
"idiom": "universal",
"filename": "Default@3x~universal~anyany.png",
"scale": "3x"
},
{
"appearances": [
{
"appearance": "luminosity",
"value": "dark"
}
],
"idiom": "universal",
"scale": "1x",
"filename": "Default@1x~universal~anyany-dark.png"
},
{
"appearances": [
{
"appearance": "luminosity",
"value": "dark"
}
],
"idiom": "universal",
"scale": "2x",
"filename": "Default@2x~universal~anyany-dark.png"
},
{
"appearances": [
{
"appearance": "luminosity",
"value": "dark"
}
],
"idiom": "universal",
"scale": "3x",
"filename": "Default@3x~universal~anyany-dark.png"
}
],
"info": {
"version": 1,
"author": "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Some files were not shown because too many files have changed in this diff Show More