This commit adds support for the LN checkout flow, and the Purple
landing page:
1. It adds a "learn more" button on the Damus Purple view, where the
user can learn more
2. It adds new `damus:purple` urls to enable the LN checkout flow
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
... to shared container instead of migrating
This commit is a reimplementation of DamusUserDefaults that mirrors
settings from the app to the shared container (instead of migrating
values over).
This new implementation brings the benefit of being backwards compatible
with the user's settings. That is, even if the user upgrades or
downgrades between various versions and changes settings along the way,
the main settings in the app will stay consistent between Damus versions
— that is, changes to the settings would not be lost between
downgrades/upgrades
General settings test
----------------------
PASS
Device: iPhone 15 Pro simulator
iOS: 17.0.1
Damus: This commit
Setup: A device with non-standard settings
Steps:
1. Flash Damus on the device
2. Check any non-default settings that were there before. Ensure that settings remained the same. PASS
3. Change one setting (any setting) to a non-default value
4. Restart Damus
5. Ensure settings change in step 3 persisted on the device
Notification settings test
--------------------------
PASS
Device: iPhone 15 Pro simulator
iOS: 17.0.1
Damus: This commit
Setup:
- Two phones running Damus on different accounts
- Local relay with strfry-push-notify test setup
- Apple push notification test tool
Coverage:
1. Mention notifications
2. DM notifications
3. Reaction notifications
4. Repost notifications
Steps for each notification type:
1. Use the secondary phone to generate a push notification
2. Trigger the push notification (Send push notification from test tool)
3. Ensure that the notification is received on the other device
4. Turn off notifications for that notification type on settings
5. Trigger the same push notification (Resend push notification from test tool)
6. Ensure that the notification is not received on the other device
7. Turn on notifications for that notification type on settings
8. Trigger the same push notification (Resend from test tool)
9. Ensure that notification appears on the device
Result: PASS (notifications are received when enabled and not received when disabled)
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
Unit tests
-----------
Device: iPhone 15 Pro simulator
iOS: 17.0.1
Damus: This commit
Steps: Run unit tests
Result: No regressions found (Tests either pass or they were already failing before the patches)
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
Muted users + unfollowed users test
------------------------------------
PASS
Device: iPhone 15 Pro simulator
iOS: 17.0.1
Damus: This commit
Setup:
- Two phones running Damus on different accounts
- Local relay with strfry-push-notify test setup
- Apple push notification test tool
Steps:
1. Unfollow the user who is the author of the saved notifications
2. Disable notifications for people you don't follow
3. Trigger a push notification (Resend push notification from test tool)
4. Ensure that the notification is not received on the other device
5. Enable notifications for people you don't follow
6. Trigger a push notification (Resend push notification from test tool)
7. Ensure that the notification is received on the other device
8. Mute the user who is the author of the saved notifications
9. Trigger a push notification (Resend push notification from test tool)
10. Ensure that the notification is not received on the other device
11. Unmute the user who is the author of the saved notifications
12. Trigger a push notification (Resend push notification from test tool)
13. Ensure that the notification is received on the other device
Result: PASS
Closes: https://github.com/damus-io/damus/issues/1705
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
Notification settings test
--------------------------
PASS
Device: iPhone 15 Pro simulator
iOS: 17.0.1
Damus: This commit
Setup:
- Two phones running Damus on different accounts
- Local relay with strfry-push-notify test setup
- Apple push notification test tool
Coverage:
1. Mention notifications
2. DM notifications
3. Reaction notifications
4. Repost notifications
Steps for each notification type:
1. Trigger a push notification (Resend push notification from test tool)
2. Ensure that the notification is received on the other device
3. Turn off notifications for that type on settings
4. Trigger a push notification (Resend push notification from test tool)
5. Ensure that the notification is not received on the other device
Result: PASS (notifications are received when enabled and not received when disabled)
Closes: https://github.com/damus-io/damus/issues/1764
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
The code paths for generating zap notifications were very different from
the paths used by most other notifications. In this commit, I include
the logic and data structures necessary for formatting zap notifications
in the same fashion as local notifications.
A good amount of refactoring and moving functions/structures around was
necessary to reuse zap local notification logic. I also attempted to
make the notification generation process more consistent between zaps
and other notifications, without changing too much of existing logic to
avoid even more regression risk.
General push notifications + local notifications test
-----------------------------------------------------
PASS
Device: iPhone 15 Pro simulator
iOS: 17.0.1
Damus: This commit
Setup:
- Two phones running Damus on different accounts
- Local relay with strfry-push-notify test setup
- Apple push notification test tool
Coverage:
1. Mention notifications
2. DM notifications
3. Reaction notifications
4. Repost notifications
Steps for each notification type:
1. Trigger a notification (local and then push)
2. Ensure that the notification is received on the other device
3. Ensure that the notification is formatted correctly
4. Ensure that DMs are decrypted correctly
5. Ensure that profile names are unfurled correctly
6. Click on the notification and ensure that the app opens to the correct screen
Result: PASS (all notifications received and formatted correctly)
Notes:
- For some reason my relay is not receiving zap events, so I could not
test zap notifications yet.
- Reply notifications do not seem to be implemented yet
- These apply to the tests below as well
Changelog-Added: Zap notification support for push notifications
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
Testing
-------
Conditional pass
Device: iPhone 15 Pro simulator
iOS: 17.0.1
Damus: This commit
Coverage:
1. Mention notification works (local and push). PASS
2. Thread replies do not appear (but upon code inspection it seems like
it was not supported before). PASS?
3. DM notification works with decryption (local and push). PASS
4. Zaps not yet implemented. Coming later.
Closes: https://github.com/damus-io/damus/issues/1702
Closes: https://github.com/damus-io/damus/issues/1703
Changelog-Changed: Improve push notification support to match local notification support
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
This is needed to allow the notification extension to process push notifications, respect user's notification settings, and decrypt DMs on the push notification
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
This commit brings key local notification logic into the notification
extension target to allow the extension to reuse much of the
functionality surrounding the processing and formatting of
notifications. More specifically, the functions
`process_local_notification` and `create_local_notification` were
brought into the extension target.
This will enable us to reuse much of the pre-existing notification logic
(and avoid having to reimplement all of that)
However, those functions had high dependencies on other parts of the
code, so significant refactorings were needed to make this happen:
- `create_local_notification` and `process_local_notification` had its
function signatures changed to avoid the need to `DamusState` (which
pulls too many other dependecies)
- Other necessary dependencies, such as `Profiles`, `UserSettingsStore`
had to be pulled into the extension target. Subsequently,
sub-dependencies of those items had to be pulled in as well
- In several cases, files were split to avoid pulling too many
dependencies (e.g. Some Model files depended on some functions in View
files, so in those cases I moved those functions into their own
separate file to avoid pulling in view logic into the extension
target)
- Notification processing logic was changed a bit to remove dependency
on `EventCache` in favor of using ndb directly (As instructed in a
TODO comment in EventCache, and because EventCache has too many other
dependencies)
tldr: A LOT of things were moved around, a bit of logic was changed
around local notifications to avoid using `EventCache`, but otherwise
this commit is meant to be a no-op without any new features or
user-facing functional changes.
Testing
-------
Device: iPhone 15 Pro
iOS: 17.0.1
Damus: This commit
Coverage:
1. Ran unit tests to check for regressions (none detected)
2. Launched the app and navigated around and did some interactions to
perform a quick functional smoke test (no regressions found)
3. Sent a few push notifications to check they still work as expected (PASS)
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
This commit adds support for the unfurling of author profile names on remote push notifications
It also makes the following changes:
- Notification extension now uses NdbNote
- Some of the logic between push notifications and local notifications was unified
Testing
-------
Device: iPhone 15 Pro simulator
iOS: 17.0.1
Damus: This commit
Coverage:
1. Basic smoke tests on the app by browsing different notes and different tabs
2. Sent test push notifications for mentions and DMs to check the unfurling of profile names
3. Ran unit tests
Closes: https://github.com/damus-io/damus/issues/1703
Changelog-Added: Unfurl profile name on remote push notifications
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
This commit integrates the Damus Purple translation service:
- Automatically handles translation settings change after purchase
- Asks for permission to override translation settings if the user already has translation setup
- Translation settings can be changed with Damus Purple, if desired
- Translation requests working with the Damus API server
Testing
--------
PASS
Device: iPhone 15 simulator
iOS: 17.2
Damus: This commit
Damus Purple API server: `9397201d7d55ddcec4c18fcd337f759b61dce697` running on Ubuntu 22.04 LTS VM (npm run dev)
iOS setting: English set as the only preferred language.
Steps:
1. Enable Damus Purple feature flag on developer settings, set purple localhost mode, and restart app
2. Set translation setting to something other than none (e.g. DeepL)
3. Simulate Damus Purple purchase
4. Check that when dismissing welcome view, a confirmation prompt will ask the user whether they want to switch translator to Damus Purple. PASS
5. Click "Yes".
6. Go to translation settings. Check that translation settings are set to "Purple". PASS
7. Go to a non-English profile. Check that translations appear with "Mock translation" (Which is the translation text provided by the mock translation server). PASS
8. Reinstall app
9. Repeat the test, but this time starting with no translation settings. Make sure that translation settings will automatically switch to Damus Purple. PASS
Feature flag testing
--------------------
PASS
Preconditions: Same as above
Steps:
1. Turn off translation
2. Turn off Damus Purple feature flag
3. Go to translation settings. Make sure that Damus Purple is not an option. PASS
Closes: https://github.com/damus-io/damus/issues/1836
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
these changes were made to adapt the client-side to the new improvements
done to the Purple API server (See
https://github.com/damus-io/api/issues/1)
Testing
-------
PASS
Device: iPhone 15 Pro simulator
iOS: 17.2
Damus: This commit
damus-api: bda56590be7eb47e21dfd61ab94b17f6a8595d0c
Server: Ubuntu 22.04 (VM)
Setup:
1. On the server, delete the `mdb` database files to start from scratch
2. Enable subscriptions support via developer settings with localhost
test mode and restart app
3. Get Damus Purple (Purchase it via Xcode test environment)
4. Start server with mock parameters (Run `npm run dev`)
5. Restart app
Steps
-----
1. Post something
2. Gold star should appear beside your name
3. Look at the server logs. There should be some requests to create the
account (POST), to send the receipt (POST), and to get account
status. Those three requests should have returned HTTP status 200.
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
Testing
---------
PASS
Device: iPhone 15 Pro simulator
iOS: 17.2
Damus: This commit
damus-api: 626fb9665d8d6c576dd635d5224869cd9b69d190
Server: Ubuntu 22.04 (VM)
Setup:
1. On the server, delete the `mdb` database files to start from scratch
2. In iOS, reinstall the app if necessary to make sure there are no in-app purchases
3. Enable subscriptions support via developer settings with localhost test mode and restart app
4. Start server with mock parameters (Run `npm run dev`)
Steps:
1. Open top bar and click on "Purple"
2. Purple screen should appear and show both benefits and the purchase options. PASS
3. Click on "monthly". An Apple screen to confirm purchase should appear. PASS
4. Welcome screen with animation should appear. PASS
5. Click continue and restart app (Due to known issue tracked at damus-io#1814)
6. Post something
7. Gold star should appear beside your name
8. Look at the server logs. There should be some requests to create the account (POST), to send the receipt (POST), and to get account status
9. Go to purple view. There should be some information about the subscription, as well as a "manage" button. PASS
10. Click on "manage" button. An iOS sheet should appear allow the user to unsubscribe or manage their subscription to Damus Purple.
Closes: https://github.com/damus-io/damus/issues/1809
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
This commit includes various code changes necessary to get a basic proof of concept of the feature working.
This is NOT a full working feature yet, only a preliminary prototype/PoC. It includes:
- [X] Basic Storekit configuration
- [X] Basic purchase mechanism
- [X] Basic layout and copywriting
- [X] Basic design
- [X] Manage button (To help user cancel their subscription)
- [X] Thank you confirmation + special welcome view
- [X] Star badge on profile (by checking the Damus Purple API)
- [X] Connection to Damus purple API for fetching account info, registering for an account and sending over the App Store receipt data
The feature sits behind a feature flag which is OFF by default (it can be turned ON via Settings --> Developer settings --> Enable experimental Purple API and restarting the app)
Testing
---------
PASS
Device: iPhone 15 Pro simulator
iOS: 17.0.1
Damus: This commit
damus-api: 59ce44a92cff1c1aaed9886f9befbd5f1053821d
Server: Ubuntu 22.04 (VM)
Setup:
1. On the server, delete the `mdb` database files to start from scratch
2. In iOS, reinstall the app if necessary to make sure there are no in-app purchases
3. Enable subscriptions support via developer settings with localhost test mode and restart app
4. Start server with mock parameters (Run `npm run dev`)
Steps:
1. Open top bar and click on "Purple"
2. Purple screen should appear and show both benefits and the purchase options. PASS
3. Click on "monthly". An Apple screen to confirm purchase should appear. PASS
4. Welcome screen with animation should appear. PASS
5. Click continue and restart app (Due to known issue tracked at https://github.com/damus-io/damus/issues/1814)
6. Post something
7. Gold star should appear beside your name
8. Look at the server logs. There should be some requests to create the account (POST), to send the receipt (POST), and to get account status
9. Go to purple view. There should be some information about the subscription, as well as a "manage" button. PASS
10. Click on "manage" button. An iOS sheet should appear allow the user to unsubscribe or manage their subscription to Damus Purple.
Feature flag testing
--------------------
PASS
Preconditions: Continue from above test
Steps:
1. Disable Damus Purple experiment support on developer settings. Restart the app.
2. Check your post. There should be no star beside your profile name. PASS
3. Check side menu. There should be no "Damus Purple" option. PASS
4. Check server logs. There should be no new requests being done to the server. PASS
Closes: https://github.com/damus-io/damus/issues/1422
This commit fixes a crash that occured on large notes with several artifacts.
The crash was caused by an empirically observed limitation on the amount
of `Text` objects that can be added together. Adding several `Text`
objects together causes a infinite recursion and subsequent stack
overflow.
The fix applied changes the `CompatibleText` class to store several
items in a list, which concatenates attributed strings when possible to
reducethe amount of `Text` objects used.
This commit also:
- Changes the structure to avoid storing SwiftUI objects on a variable,
but making it into a computed property instead.
- Renders a nice error message when the note is too large to be rendered
(instead of crashing)
With this new commit, we can render much larger notes, and the only ones
that will not be displayed are those containing more than 50 custom
hashtags.
Since we do not even have 50 custom hashtag types, the only notes that
won't be rendered are spammy notes that repeat the same hashtags over
and over again.
Testing
-------
PASS
Device: iPhone 13 Mini (Physical device)
iOS: 17.2
Damus: This commit
Setup:
- Local test relay and a test account running on a simulator to post
those long test notes.
- Local web page server to serve a link to the problematic note.
(nostr:note1ttfgneka3lt6yuutmr0uls5xd6z975fgdzpfkxwwf40dd38pjcqqvzvxaj)
Steps
-----
1. Click on the link to open the note
2. Check that no crash occurs and that the note is rendered correctly. PASS
3. Click on the note to render the SelectableText view (Different code
path). Make sure that no crash occurs and that it is rendered
correctly. PASS
4. On the simulator, post a note with 50 "#bitcoin" hashtags displayed
(100 items).
5. Open the note on the physical iPhone. Make sure that no crash occurs
and that the note is rendered correctly. PASS
6. Ensure that the hashtag and hashtag icons are rendered. PASS
7. Click on the note and make sure that the SelectableText view is
rendered correctly. PASS[1]
8. On the simulator, post a note with 51 "#bitcoin" hashtags displayed
(102 items).
9. Open the note on the physical iPhone. Make sure that a nice error
message is displayed. PASS
10. Click on the note and make sure that the SelectableText view is
rendered correctly. PASS[1]
Notes
[1] On the SelectableText view, special hashtags always render with the
purple color. This behavior was already present before the changes, so
it is not a regression.
Changelog-Fixed: Fix crash on very large notes
Closes: https://github.com/damus-io/damus/issues/1826
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
This reverts commit da2bdad18d.
This commit was reverted because it was causing crashes (Occasional `EXC_BAD_ACCESS` errors when accessing database transactions), and because the push notification extension uses Ndb in a read-only manner, which means we no longer need these changes
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This patch makes sure that regional relays (e.g. Japan relays) are suggested to the relevant users on the Relay configuration view.
It also makes some small improvements to the recommended relays view layout, to allow it to comfortably show more than 4 relay suggestions without "squeezing" items.
Testing
-------
PASS
Devices:
- iPhone 15 Pro simulator running iOS 17.0.1
- iPad Air 5th generation running iOS 16.4
Damus: This commit
Configuration: No relays selected, region set to Canada
Steps:
1. Go to Relay Config view
2. Check that recommended relays are: Damus, nos.lol, nostr.wine, nostr.land. PASS
3. Change region to Japan on settings
4. Open relay config view again
5. Check that Japan relays are suggested on top of the list presented in step 2. PASS
6. Check that layout looks ok, not broken. PASS
7. Check that it is possible to scroll horizontally to see all the options. PASS
8. Add some relays. Check that it is possible to add relays. PASS
9. Check that borders of the recommended relay view fades away nicely (not just clip). PASS
10. Remove some relays. Check that they return to the suggested relays list. PASS
Real device smoke test
----------------------
Device: iPhone 13 mini running iOS 17.1
Damus: This commit
Configuration: Several relays selected. Region set to Canada.
Steps:
1. Check relay config view does not look broken. PASS
2. Remove some recommended relays. Check that they display nicely on the recommended view. PASS
3. Scroll horizontally. Scrolling should work and layout should not be broken. PASS
4. Add those recommended relays again. Should work. PASS
Closes: https://github.com/damus-io/damus/issues/1730
Changelog-Added: Add regional relay recommendations to Relay configuration view (currently for Japanese users only)
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
This commit adds region-specific relays for Thailand and Germany. The list was blindly copied and pasted from the tickets.
Testing
-------
Device: iPhone 15 Pro simulator
iOS: 17.0.1
Damus: A locally modded version combining these changes with changes made in #1730 (A bit hacky, but makes testing faster)
Steps:
1. Change region to Canada. Only international relays should be shown in recommended relay list. PASS
2. Change region to Japan. International + Japanese relays should be shown in the recommended list. PASS
3. Repeat step (2) for Thailand and Germany. International + corresponding regional relays should be shown. PASS
Changelog-Added: Add regional relays for Thailand
Closes: https://github.com/damus-io/damus/issues/1698
Changelog-Added: Add regional relays for Germany
Closes: https://github.com/damus-io/damus/issues/1750
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
This change was made so that NostrDB data can be accessed from different build targets such as the notification service extension.
Upon initialization of NostrDB, it will check both DB file locations (the old documents directory, and the new shared app group container). If it sees the DB is present on the old location, and not on the new location, it will move the files to the new location. In any other condition it will keep the files intact to prevent data loss.
In order to avoid any conflicts between the damusApp's Ndb instance and the extension's Ndb instance when writing or moving the file, a new parameter called "owns_db_file" was added, and set to "false" for the extension. This ensures that the extension will not attempt to move DB files or create a new DB file on its own. Only the main app can move or create the DB file.
Testing
-------
PASS
Device: iPhone 15 Pro simulator
iOS: 17.0.1
Damus: This commit
Steps:
1. Run with the debugger attached to the extension target.
2. Using Apple's push notification testing dashboard, send a test push notification with a real payload (that includes the nostr event under `nostr_event`. Payload generated by strfry-push-notify).
3. Watch logs. It should show a message like "Got push notification from <DISPLAY_NAME>", where `DISPLAY_NAME` is the correct profile name of the user who generated the event. PASS
Regression testing
------------------
Device: iPhone 13 Mini (Real device)
iOS: 17.1.1
Damus: This commit
Other preconditions:
- Damus is at 1.6 (29) at the start of the test
- NostrDB filled with real data on the old location
Steps:
1. Flash (upgrade) the new Damus version (this commit) (This will be the first time upgrading, shared file container is empty)
2. Try to use the app normally. Scroll and navigate to several locations. Interact with some notes. App should be stable, work, and appear to have profile names already (i.e. It shouldn't start with a bunch of npubs in the place of profile names on known contacts). PASS
3. Downgrade back to the App store version (v1.6 (29))
4. Try to use the app normally. Scroll and navigate, interact, etc. App should work and be stable, but profile name cache is expected to be lost (i.e. shows npubs for a bit until profile is reloaded into NostrDB). PASS
5. Upgrade app again to the version in this commit.
6. Repeat step 2. Everything should work as normal and all profiles should be preloaded from the start. PASS
Closes: https://github.com/damus-io/damus/issues/1744
This change includes several source files related to NostrDB into the extension target as well, so that we can use it from that context (and thus enable more advanced push notification formatting and suppression)
To make this change possible, I had to split some source files as well as to move some functions to different files, to ensure we don't have to pull too much unnecessary code into the extension.
Testing
-------
PASS
Device: iPhone 15 Pro simulator
iOS: 17.0.1
Damus: This commit
Test steps:
1. Build DamusNotificationService. Should succeed. PASS
2. Build Damus (the app). PASS
3. Run app, scroll around some notes, go to a few different views, post a note. Should work as normal. PASS
I added support for the experimental push notifications feature. There are many improvements to be made, so this feature is currently opt-in only. If the user does not opt-in, their device tokens will not be sent out and thus they will receive no push notifications.
We should perform more testing on real-life staging environments before fully releasing this feature.
Testing
-------
Testing was done gradually during development.
Device: iOS simulators
iOS: 17
Damus version: A few different but recent prototypes
Rough coverage:
1. Checked that no device tokens are sent out when setting is off
2. Checked that I can successfully receive device tokens when feature is ON and set to localhost.
3. Checked sending test push notifications of types "note" (kind: 1), reaction (kind: 7) and DMs (kind 4) works and shows a generic but reasonable push notification message
4. Checked that clicking on the notifications above take the user to the correct screen
Closes: https://github.com/damus-io/damus/issues/67
Changelog-Added: Add experimental push notification support
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
This commit fixes the issue where clicking "post" on the onboarding sheet does not dismisses itself under certain device/iOS combos.
The root cause is that the behavior of `dismiss` calls under a deeply nested view (i.e. not a direct subview of the sheet) is inconsistent depending on the device or iOS.
This fix does two things:
1. It upgrades the usage of `presentationMode` (which is deprecated) to the new `dismiss` API
2. It makes the onboarding sheet view (A direct subview of the sheet) to listen to signals from the post view and use that to also call `dismiss()`, which is explicitly supported by Apple in their docs (https://developer.apple.com/documentation/swiftui/environmentvalues/dismiss)
Testing
-------
PASS
Device: iPhone 13 mini (physical device)
iOS: 17.1
Damus: This commit (Local build, no local mods)
Setting: "Always show onboarding" is set to ON
Coverage:
1. Clicking "post" on onboarding post view publishes the post and dismisses the view. PASS
2. Clicking "cancel" on onboarding post view dismisses the view without publishing. PASS
3. Dragging the onboarding post view down dismisses the view without publishing. PASS
4. Making a normal post (I replied to a thread) still publishes the post and dismisses the normal post view sheet. PASS
Testing on other Device/iOS combos
---------------------------------
PASS
Preconditions:
- iPhone 15 Pro (simulator) on iOS 17.0.1
- iPhone SE 3rd gen (simulator) on iOS 16.4
Damus: This commit (Local build, no local mods)
Setting: "Always show onboarding" is set to ON
Coverage:
1. Clicking "post" on onboarding post view publishes the post and dismisses the view. PASS
Closes: https://github.com/damus-io/damus/issues/1726
Changelog-Fixed: Fix onboarding post view not being dismissed under certain conditions
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
I am setting the expiration values lower because it seems that the previous values were not keeping storage usage low enough.
Testing: Testing will be performed as a long-term test on Github issue #1689 (https://github.com/damus-io/damus/issues/1689)
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
This changes the text that appears on the camera permission dialog, and makes it clear that camera access is also needed for the scanning of QR codes. This change was made to address a concern raised during the Apple app review process.
Testing
-------
PASS
Device: iPhone 13 Mini (physical)
iOS: 17.1
Damus: This commit
Special remarks: I locally modified the bundle identifier to be able to install a fresh copy of Damus from scratch and go through the prompt, without having to uninstall my own copy of Damus
Steps:
1. Install a fresh copy of Damus
2. On account creation, try to scan an nsec.
3. Make sure the camera usage prompt message is modified to the new string.
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
This commit adds a new setting that can be used by developers to test onboarding suggestions without having to make local changes to code or reinstall the app.
Testing
-------
Device: iPhone 15 Pro (Simulator)
iOS: 17.0.1
Damus: This commit
Coverage:
1. Starting the existing app under the default setting does not show onboarding suggestions
2. Turning the setting ON causes the app to show onboarding suggestions on every app restart
3. Turning the setting back OFF causes the app to no longer show onboarding suggestions
Changelog-Added: Add "Always show onboarding suggestions" developer setting
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
Depending on user's locale. currently only supported for Japanese users.
This change allows Japanese users to automatically connect with popular
Japanese regional relays during account creation, thus allowing Japanese
users to better connect with the Japanese Nostr community.
More specifically, 3 Japanese regional relays will be automatically
added to the user's relay list (on top of the usual relays) under the
following conditions:
1. User's region (As configured in iOS settings) is Japan, AND
2. The user is creating a new Nostr account through Damus.
In the case the Nostr account is not new, Damus will not add any
regional relays (It will respect the user's relay list).
Testing
-------
PASS
Device: iPhone 15 Pro (Simulator)
iOS: 17.0.1
Damus: This commit
Test steps:
1. With the US region set, install Damus
2. Go through onboarding and create a new account.
3. Once the onboarding is complete, look at the connected relays. Should only be connected with popular international relays. PASS
4. Uninstall Damus
5. On iOS settings, go to Location & Region settings and change the region to Japan.
6. Install Damus
7. Go through onboarding and create a new account.
8. Once the onboarding is complete, look at the connected relays. User should be connected with intl relays as well as Japanese relays. PASS
9. Quit Damus and restart
10. Ensure the Japanese relays are still on the list. PASS
11. Quit Damus
12. Change region back to US
13. Restart Damus and check the relay list. Relay list should not be affected. PASS
14. Reinstall Damus
15. Check relay list. Only intl relays should be shown. PASS
16. Change region to Japan (JP)
17. Restart Damus and check the relay list. Relay list should not be affected. PASS
18. Reinstall Damus
19. This time, login with a pre-existing account (One that is not connected to Japanese relays).
20. After onboarding, check relay list. The relay list should be unaffected (i.e. Japanese relays should not have been added since this account is pre-existing). PASS
Note: The actual network connection with some of the Japanese relays
failed, but that is likely due to the Geo-based IP restrictions imposed
by some of those Japanese relays. The relay list has been copied
verbatim from @mattn's suggestions.
Reference ticket: https://github.com/damus-io/damus/issues/1447
Changelog-Changed: Automatically load extra regional Japanese relays during account creation if user's region is set to Japan.
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
Tested on iOS 17.0.1 on an iPhone 15 Pro simulator.
Closes: https://github.com/damus-io/damus/issues/1641
Changelog-Added: Add setting that allows users to optionally disable the new profile action sheet feature
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
This commit implements a single-tap zap on the profile action sheet and fixes an issue where zapping would silently fail on default settings if the user had no lightning wallet installed in their system.
Testing
-------
Configurations:
- iPhone 13 Mini (physical device) on iOS 17.0.2 with NWC wallet attached
- iPhone 15 Pro (simulator) on iOS 17.0.1 with no lightning wallet nor NWC
Damus: This commit
Coverage:
- Zapping using NWC connected wallet: PASS (Zaps and shows UX feedback of the completed action)
- Zapping under default settings and no lightning wallet: PASS (Shows the wallet selector invoice view)
- Long press on zap button brings custom zap view
Regression testing
------------------
Preconditions: iPhone 15 Pro (simulator) on iOS 17.0.1 with no lightning wallet nor NWC
Coverage:
- Zapping user on their full profile shows wallet selector. PASS
- On-post invoice shows wallet selector. PASS
Closes: https://github.com/damus-io/damus/issues/1634
Changelog-Changed: Zap button on profile action sheet now zaps with a single click, while a long press brings custom zap view
Changelog-Fixed: Fixed an issue where zapping would silently fail on default settings if the user does not have a lightning wallet preinstalled on their device.
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
This is a non-functional refactor to rename two views with similar names, to avoid confusion.
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
via zappability badges and profile action sheets
This commit improves discoverability of zaps with the following changes:
1. New zap icon appears on profile pictures of events where the author of such event has zaps setup
2. Clicking on a profile picture from an event shows an action sheet that makes it easier to see a preview of their profile, and a zap button
Testing
-------
Devices:
- iPhone 14 Pro simulator
- iPad 10 simulator
iOS:
- 17.0.1
- 16.4
Damus: This commit
Coverage:
1. Checked that zap icon appears on profile pictures on events in different feeds and threads
2. Checked that this zap icon only appears for profiles that have zaps enabled
3. Checked that profile action sheet looks good on both light mode and dark mode
4. Checked that long descriptions are truncated and the "see more" "see less" buttons work
5. Checked that clicking "see more" or "see less" adapts the size of the action sheet (on iPhone)
6. Checked that action sheet looks good whether or not the user has a website link setup
7. Checked that long presses on the zap button in the action sheet bring the same options as the normal profile view
8. Checked all the buttons in the action sheet take the user to the expected place
9. Checked that the original profile view looks good (on both light and dark mode)
Notes:
- Action sheet cannot be resized on iPad.
- Could not test on Mac Catalyst because there seems to be a crash on the creation of a new account
Reference ticket: https://github.com/damus-io/damus/issues/1596
Changelog-Added: Improve discoverability of profile zaps with zappability badges and profile action sheets
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
This commit adds a suggested hashtag section to the universe view tab. The method for suggesting hashtags is currently simple:
1. It contains a list of many possible hashtags that we could recommend
2. It calculates how many users have been talking about it in the events fetched by the Universe tab
3. It selects the Top-N most mentioned suggested hashtags in the Universe tab
This has the following properties:
1. It has some spam resistance as it ranks by unique users mentioning the tag (instead of events)
2. It is a simple way to curate good hashtags
3. It shows the ones with the most amount of people talking about it among the notes fecthed in the Universe view
Testing
-------
PASS
Device: iPhone 14 Pro simulator
iOS: 17.0
Damus: This commit
Coverage:
1. Suggested hashtags are displayed
2. Layout looks similar to Figma
3. User count goes up (does not stay at zero)
4. Clicking on a suggested hashtag takes you to that hashtag view
5. Only the top 5 hashtags are displayed
Notes: The counts seem low, probably because there are not enough notes loaded in Universe View
Changelog-Added: Add suggested hashtags to universe view
Closes: https://github.com/damus-io/damus/issues/1569
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
Testing of standard flow
------------------------
PASS
Device: iPhone 14 Pro simulator
iOS: 17.0
Damus: This commit
Steps:
1. Delete and reinstall Damus
2. Go through onboarding until suggested users appear
3. Click "continue". Should slide into the post view. PASS
4. Post view should look similar to the Figma design file, but with examples as placeholders. PASS
5. Examples should switch every 3 seconds. PASS
6. Typing a first character causes the #introductions hashtag to be automatically added. PASS
7. Uploading an image makes progress view show up and not break layout. PASS
8. Clicking on "post" should post this note and dismiss onboarding view. PASS
Testing of other flows
----------------------
PASS
Device: iPhone 14 Pro simulator
iOS: 17.0
Damus: This commit
Special remark: Made local change to always show the onboarding suggestions, and speed up testing
Coverage:
1. Clicking "skip" on suggested users view will skip into the post view. PASS
2. Clicking "cancel" on post view and then going to the normal post view reveals a blank draft. PASS
3. Clicking "cancel" dismisses onboarding view and does not post anything. PASS
4. Normal post view looks normal (not broken). PASS
5. Changing initial suggested post during onboarding, cancelling the post, and then re-entering normal post view reveals the draft with user modifications. PASS
Changelog-Added: Suggest first post during onboarding
Closes: https://github.com/damus-io/damus/issues/1338
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
This commits causes DMs from muted users to be filtered out. It also fixes an issue where the DM list would appear completely blank in certain scenarios.
Testing
-------
CONDITIONAL PASS
Device: iPhone 14 Pro simulator
iOS: 17.0
Damus: This commit
Setup:
- Three test accounts (A, B, and C). "A" will be the account running on the device under test.
- Account "A" should start with no DMs
1. Send a direct message from "B" to "A", and reply from "A".
2. Go to DMs -> DMs tab. Conversation with "B" should appear. PASS
3. Mute user "B" (I did it via profiles page).
4. Go back to DMs view via back button. DMs from "B" should not appear. PASS
5. Since there are no DMs, the screen should display "Nothing to see here". PASS
5. Close Damus app via iOS app switcher and reopen Damus
6. Check DMs list. Should only show "Nothing to see here". PASS
7. Send a DM from account "C" to "A" and reply.
8. Go back to DMs -> DMs tab. Only the message from account "C" should appear.
9. Unmute user "B"
10. Go back to DMs. Messages from "B" and "C" should appear. PASS
Notes:
- There was one instance when the first DM from account "C" appeared in the "DMs" tab (Not "requests") momentarily. After a bit it went into requests as expected.
- When unmuting user "B", I had to refresh the DM list by switching tabs, meaning that the view did not immediately update.
Upon inspection, the two behaviors above are not caused by this change, so this is a conditional pass.
Closes: https://github.com/damus-io/damus/issues/1350
Changelog-Fixed: Do not show DMs from muted users
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
This commit adds a basic snapshot test for EventView, and also adds some testing infrastructure to help with mocking NostrDB behavior.
Test
----
PASS
Device: iOS 17.0 Simulator
iOS: 17.0
Damus: This commit
Steps: Run `EventViewTests`
Results: Snapshot matches baseline reference added
This commit adds expiry dates for images added to the Kingfisher cache.
The expiry date depends on the context of the image:
- Images from notes expire after a week
- Images from profile banners expire after two weeks
- Profile pictures never expire.
Test
----
Device: iPhone 14 Pro (Simulator), iOS: 17.0
Special remarks: Requires minor local mods and debugger connection
Steps:
1. Locally change the note image expiry to 5 seconds
2. Set a breakpoint in `removeExpiredValues` function in `DiskStorage.swift` in Kingfisher
3. Disable breakpoints for now
4. Start Damus and go to the profile feed of someone new
5. Scroll down through the images for about a minute
6. Turn on breakpoints
7. Switch to a different app in the simulator (Make Damus go to background mode)
8. Wait for a few seconds. Debugger should hit the breakpoint set. PASS
9. Take note of the fileURLs of the images being deleted
10. Go to that directory where the fileURLs are in via Finder
11. Look at some of the images being deleted. Perhaps save a copy for comparison.
12. Turn off breakpoints, resume execution and go back to Damus
13. Scroll back up. Some images there should match the images being automatically deleted from the cache. PASS
Closes: https://github.com/damus-io/damus/issues/1565
Changelog-Added: Add expiry date for images in cache to be auto-deleted after a preset time to save space on storage
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
This change adds `https://github.com/pointfreeco/swift-snapshot-testing` as a package dependency and links it to the `damusTests` target.
It also adds one snapshot test to demonstrate its usefulness, by adding coverage to one particular aspect that we have never been able to test before: Whether or not the post text editor will wrap the text once the text gets long.
Testing of the test
-------------------
PASS
iOS: 17.0
Device: Simulator
Damus: This commit
Test steps:
1. Run `testTextWrapperViewWillWrapText`. PASS
2. Change TextViewWrapper.swift and remove this line:
```
textView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
```
3. Rerun. It fails. PASS (This is expected)
Closes: https://github.com/damus-io/damus/issues/1562
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
This patch improves clear cache functionality by:
- Reducing kingfisher cache removal to one command (The two commands running async was leading to warning logs. One was a subset of the other)
- Removing all files under the cache folder where not currently used by other processes
Full Functionality test
-----------------------
PASS
Device: iPhone 13 mini (Physical device)
iOS: 17.0.3
Damus: This commit
Special remarks:
- I had to locally delete other unit tests to be able to build the test target
- Unit test run on an earlier version of the patch. Test coverage should still apply since this newer patch is a subset of the previous.
Setup: Run Damus with debugger connection to Xcode
Test steps:
1. Follow multiple active accounts (Skip if local Damus is already filled up with GBs of data)
2. Scroll down on the feed for a couple of minutes (or until you have seen at least a few images, a few videos, and link previews) (Skip if local Damus is filled up with GBs of data)
3. In Xcode, download a storage container (Window > Devices and Simulators > Select the device > Select Damus > click on (...) > Download container)
- Note: Even though you see the file, it does not download instantly. Monitor the file size until it roughly reaches the size reported in iOS storage settings, as the download may still be in progress. This may take a few minutes in some cases.
- Also take note of storage usage in iOS settings
4. Open the app data package using terminal
5. Run `du -h . | sort -hr`
6. Clear cache and check logs. Logs should indicate the caches being cleared, and there should be no storage-related warning/error logs. PASS
7. Download a new storage container. Remember to wait until it completes download.
8. Run `du -h . | sort -hr` on it.
9. Compare. There should be much less data. Also check iOS settings storage usage. PASS
10. Go back to the home feed and start scrolling, browsing, follow some other people, etc. Look at your own profile as well. Everything should appear to be working as expected with no crashes or important data loss
11. Check bookmarks are still present. PASS
12. Run `DamusCacheManagerTests`. Should pass. PASS* (*See special remarks)
Results:
- Storage usage goes from 3.9GB to 394.7MB
- Damus works as normal after clearing cache, and after restarting the app as well. It becomes slower for a moment, but after a bit it loads as normal again.
- No warning or error logs pertaining to clearing cache
- Unit test passes
My storage container disk usage stats after clearing cache:
```
% du -h | sort -hr
359M ./AppData
359M .
336M ./AppData/Documents
23M ./AppData/Library
20M ./AppData/Library/Caches
7.9M ./AppData/Library/Caches/com.jb55.damus2
2.4M ./AppData/Library/SplashBoard/Snapshots
2.4M ./AppData/Library/SplashBoard
1.8M ./AppData/Library/SplashBoard/Snapshots/com.jb55.damus2 - {DEFAULT GROUP}
1.6M ./AppData/Library/Caches/com.jb55.damus2/fsCachedData
636K ./AppData/Library/SplashBoard/Snapshots/sceneID:com.jb55.damus2-ecc156b1-eb9c-4439-b219-e1eebf2b4c36
596K ./AppData/Library/Caches/com.apple.WebKit.GPU/com.apple.metal
596K ./AppData/Library/Caches/com.apple.WebKit.GPU
452K ./AppData/Library/Caches/com.jb55.damus2/com.apple.metal
296K ./AppData/Library/SplashBoard/Snapshots/sceneID:com.jb55.damus2-ecc156b1-eb9c-4439-b219-e1eebf2b4c36/downscaled
224K ./AppData/Library/HTTPStorages/com.jb55.damus2
224K ./AppData/Library/HTTPStorages
164K ./AppData/Library/Caches/com.onevcat.Kingfisher.ImageCache.default
156K ./AppData/Library/Caches/RelayLogs
112K ./AppData/Library/Caches/com.apple.dyld
92K ./AppData/Library/Preferences
60K ./AppData/Library/Caches/com.jb55.damus2/com.apple.metal/archiveUsage.db
12K ./AppData/Library/Saved Application State/com.jb55.damus2.savedState
12K ./AppData/Library/Saved Application State
8.0K ./AppData/StoreKit
8.0K ./AppData/Library/Saved Application State/com.jb55.damus2.savedState/ecc156b1-eb9c-4439-b219-e1eebf2b4c36
4.0K ./AppData/Library/Saved Application State/com.jb55.damus2.savedState/KnownSceneSessions
4.0K ./AppData/Library/LanguageModeling/en-dynamic.lm
4.0K ./AppData/Library/LanguageModeling
4.0K ./AppData/Library/Cookies
0B ./AppData/SystemData/com.apple.SafariViewService/Library/WebKit/WebsiteData
0B ./AppData/SystemData/com.apple.SafariViewService/Library/WebKit
0B ./AppData/SystemData/com.apple.SafariViewService/Library
0B ./AppData/SystemData/com.apple.SafariViewService
```
Biggest storage used remaining is in the Documents folder where NostrDB is stored. However, we do not want to clear NostrDB, so this is expected behavior.
Changelog-Changed: Improve clear cache functionality
Closes: https://github.com/damus-io/damus/issues/1472
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
This change addresses an issue where notes with quotes sometimes are not loaded correctly because the quoted note was not available in the same relay. Now whenever a user posts a note with a quoted note, the quoted note is also broadcast to the user's selected relays.
Issue repro
-----------
ISSUE REPRODUCED
Device: iPhone 14 Pro Simulator
iOS: 17.0
Damus: `1fabd4c0fe98d1f47b1fa0f76984ad78095bd49c`
Setup:
- Make sure you have a debugger connected
- Have a test note that you can quote
Steps:
1. Start Damus and let logs settle
2. Observe where the last log is
3. Quote the test note
4. Copy newly generated logs and paste on a text editor.
5. Analyze those logs. Pay attention to the new note id, as well as the note id of the quoted event (`["q", <QUOTED_NOTE_ID>]`)
Results: Logs show that the newly posted event is being flushed to the relays, but not the note that is being quoted.
Testing of the fix
------------------
PASS
Device: iPhone 14 Pro Simulator
iOS: 17.0
Damus: This commit
Setup:
- Make sure you have a debugger connected
- Have a test note that you can quote
Steps:
1. Start Damus and let logs settle
2. Observe where the last log is
3. Quote the test note
4. Copy newly generated logs and paste on a text editor.
5. Analyze those logs. Pay attention to the new note id, as well as the note id of the quoted event (`["q", <QUOTED_NOTE_ID>]`)
Results:
- Logs show the new event being flushed to the relays. PASS
- Logs show the quoted event also being flushed to the relays. PASS
Closes: https://github.com/damus-io/damus/issues/1495
Changelog-Fixed: Broadcast quoted notes when posting a note with quotes
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
Resolves build errors on the test target while we work on #1586
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
Features:
- Merch button on sidebar menu
- Damus icon at the top opens sidebar
- Merch link passes `ref` param, to help with website analytics
Testing
-------
1. Ensured that link appears correctly with image on both iOS versions
2. Ensured that link takes user to the store
3. Ensured that ref param is passed to the store
4. Ensured that Damus icon opens sidebar menu
5. Ensured that when sidebar is open, clicking where the damus icon would be does not close the sidebar menu (it is behind the sidebar menu)
Closes: https://github.com/damus-io/damus/issues/845
Changelog-Added: Added merch store button to sidebar menu
Changelog-Changed: Damus icon now opens sidebar
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
Stop tab buttons from causing the root view to scroll to the top unless
user is coming from another tab or already at the root view
This fixes an issue where if you navigated within a tab and then clicked
the tab button, it would scroll to the top. Users want to be able to
navigate back to the root of a given tab without losing the scroll
position.
Now tab buttons only scroll to the top if:
- User is coming from a different tab
- User is already at the root view of the tab, and they click on the tab button again.
Issue repro
----------
1. Scroll down the home feed a bit
2. Click on one of the posts
3. Click on the home tab button at the bottom left.
**Desired behavior:**
1. First click on home button should go to home view but not scroll to top
2. Clicking on home button should only scroll to top when user is already at the root home feed view
**Current behavior:** Clicking on home button scrolls to top on step 3 (shouldn't have)
Fix testing
-----------
Steps:
1. Scroll down the home feed a bit
2. Click on one of the posts.
3. Click on the home tab button. Should go back to home view but keep scroll position. PASS
4. Click on the home tab button again. Should scroll to the top. PASS
5. Scroll down on the home tab.
6. Switch to another tab, then switch back to the home tab. Should scroll to the top of the home view. PASS
7. Scroll down on the home tab
8. Click on the home tab button. Should scroll to the top. PASS
9. Repeat steps 1–8 for DMs, Universe view, and notifications. PASS
Closes: https://github.com/damus-io/damus/issues/1580
Changelog-Fixed: Stop tab buttons from causing the root view to scroll to the top unless user is coming from another tab or already at the root view
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
This is a follow up commit to `768ab3e9e4f55b872253d55c53983c19ab4c3d8b` in issue #1531
Testing
-------
**Device:** iPhone 14 Pro simulator
**iOS:** 17.0
**Damus:** This commit
**Steps:**
1. Remove all relays.
2. Add the Damus relay.
3. Add `wss://relay.snort.social/` relay **(with trailing slash)**. Shows up on the relay list. (PASS)
4. Add `wss://relay.snort.social/v1` and `wss://relay.snort.social/v2` to the list. Both show up as separate relays (PASS)
4. Watch logs and wait for the relay list event to be sent out
5. Restart Damus (to help ensure the repro is stable)
6. Try removing the Snort relay by swiping. Relay is removed successfully (PASS)
7. Try removing the "v1" relay by clicking on "Disconnect relay" in the detail page. "v1" relay (and NOT "v2") is removed (PASS)
8. Try adding `nos.lol` from the recommended list. Added successfully. (PASS)
9. Remove `nos.lol` with a long press. (PASS)
Changelog-Fixed: Fix issue where relays with trailing slashes cannot be removed (#1531)
Closes: https://github.com/damus-io/damus/issues/1531
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
Testing
-------
PASS
Device: iPhone 14 Pro simulator
iOS: Tested on iOS 17.0 and 16.4
Steps:
1. Go to appearance settings
2. Enable animations. Shows confirmation dialog. PASS
3. Click cancel. Setting is toggled back. PASS
4. Enable animations again. This time click "OK". Setting stays at what was set, and cache is visibly cleared. PASS
5. Restart app. Changes are persistent. PASS
6. Disable animations. Dialog appears like before. PASS
7. Cancel. Toggles back as expected. PASS
8. Disable animations again. This time click "OK". Cache is cleared. PASS
7. Restart app. Changes are persistent. PASS
9. Click on "clear cache". Confirmation dialog appears. PASS
10. Cancel action. We do not see cache being cleared. PASS
11. Click on "clear cache" and click "OK" this time.
12. We can see the cache being visibly cleared. It shows a loading spinner and "clearing cache", and then we see a checkmark icon with a "cache cleared" indicator. We cannot click the button again for now. PASS
13. Go to home view, scroll through some views, then come back to the setting. Clear cache button is visible again.
Closes: https://github.com/damus-io/damus/issues/1301
Changelog-Changed: Improve UX around clearing cache
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
This change makes the text editor/composer more robust and simple and solves Github issue #1558
It builds on the changes made for #1211, and on Jericho's (Jericho Hasselbush <jericho@sal-et-lucem.com>) discovery during his work on #1544
It uses setContentCompressionResistance, disabled text box scrolling, and dynamic height adjustments (based on more accurate layout calculations) to allow several improvements:
- It ensures lines get wrapped and not overflown
- It uses system native "scroll cursor into view" when typing, eliminating the need to a ghost caret
- It ensures we do not have a scroll view within a scroll view (which is confusing)
- It ensures that we set the height of the text box to its ideal value using a native layout calculation (Removes some issues with copying and pasting larger text)
- It resolves other small issues, such as #1558
Issue #1558 repro
-----------------
Result: VERIFIED
Device: iPhone 14 Pro Simulator
iOS: 17.0
Damus: `476f52562a70c2615ad084640dd1a0ba5c4c12e3`
Issue #1558 steps:
1. Type "hello world, hello @da"
2. Select "Damus" in contact list
3. Try moving cursor to the end of "world". Cursor should have gone there, but it immediately goes back to the end of "@damus " instead.
Testing for #1558
-----------------
Result: PASS
Device: iPhone 14 Pro Simulator
iOS: 17.0
Damus: This commit
Steps:
1. Type "hello world, hello @da"
2. Select "Damus" in contact list
3. Try moving cursor to the end of "world". Cursor goes there.
General functionality testing
-----------------------------
Result: CONDITIONAL PASS.
Summary: Behaviour is improved from #1211 patch, and #1558 is fixed. There are a few remaining issues, but they do not look like regressions from these changes. More details below.
Device: iPhone 14 Pro Simulator
iOS: 17.0
Damus: This commit
Coverage:
1. Basic typing works. PASS
2. Basic user tagging works. PASS
3. Typing long text line wraps the line. PASS
4. Adding newlines to the end of the text works and text is visible (i.e. Text box is expanding with text). PASS
5. Adding lots of newlines causes the text box and inner PostView content to expand, and those contents can be scrolled. PASS
6. Typing text when cursor is out of view (both up and down) causes PostView to scroll the cursor into view. PASS
7. Tagging user on a line positioned at the middle of the screen causes view to scroll cursor into view. PASS
8. Tagging user on a very long line positioned causes view to scroll cursor into view. PASS
9. Pasting very long text (5 paragraphs of Lorem Ipsum) expands the text box as necessary, wraps all long lines, scrolls cursor at the end into view. PASS
10. Scrolling through very long text shows that there is only one scroll view active (PostView's). PASS
11. Typing text that expands text box does not cause jitters. PASS
12. Typing mentions do not cause jitter. PASS
13. Adding newline from the end of a mid paragraph unfortunately still causes cursor to jump to the end of the text. This is an existing bug (https://github.com/damus-io/damus/issues/1521). EXISTING ISSUE.
14. Tagging a user at the end of a line when there are other lines below it may cause the cursor to jump a few characters forward. It is unclear whether this is a regression because prior to this change the cursor would get stuck at the end of the mention. But since this is a very specific edge case that might not be a regression, it might be a good idea to address this on a separate ticket. CONDITIONAL PASS
15. Could not run PostView unit tests due to various build errors on the test target.
Closes: https://github.com/damus-io/damus/issues/1558
Changelog-Fixed: Fix situations where the note composer cursor gets stuck in one place after tagging a user
Changelog-Fixed: Fix some note composer issues, such as when copying/pasting larger text, and make the post composer more robust.
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
Applied the content filters to the hashtag search timeline view, to filter out #nsfw-tagged posts on that view if the user has that setting enabled.
Testing of the fix
------------------
**PASS**
**iOS:** 17.0 (iPhone 14 Pro simulator)
**Damus:** This commit
**Test steps:**
1. Search for #sauna hashtag
2. Pick one post from results that contains multiple hashtags
3. Locally change nsfw filter in the code to another hashtag (I picked #homestead in this example) (This is to make testing easier)
4. Run app on simulator
5. Disable nsfw filtering
6. Search for the #sauna hashtag
7. Ensure that the post from step 2 is there
8. Turn on nsfw filtering
9. Search for the #sauna hashtag again. Ensure that post from step 2 is no longer visible
10. Switch keyword back to #nsfw in the code. Re-run app
11. Search for the #nsfw hashtag. No posts appear (timeline view is empty). (Not sure if this is the desired behavior, but seems reasonable)
12. Turn off nsfw filtering
13. Search for the #nsfw hashtag again. #nsfw posts should appear.
Closes: https://github.com/damus-io/damus/issues/1412
Changelog-Fixed: Apply filters to hashtag search timeline view
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
Summary
-------
This fixes the issue at Github #1531 where relays with trailing slashes cannot be removed.
The root cause (Identified by @fishcakeday) was that for a relay to be removed, a certain dictionary entry containing the relay url needed to be removed prior to sending the updated relay list. However those dictionary keys used `String` objects, which cannot tell that two URLs are the same with or without a trailing slash.
To fix the issue, I have used a dictionary with the type `[RelayURL: RelayInfo]`, and made the necessary protocol conformance implementations for RelayURL. This way, URLs are handled with higher accuracy (e.g. Trailing slashes do not matter, URLs that resolve to the same location will match no matter what).
This allows us to leverage the existing parsing and handling logic that comes with the `URL` type, instead of manually handling URL strings.
Generally speaking it is preferrable to work with higher level `URL` or `RelayURL` objects than handle URLs via `String`. There is an opportunity to refactor more code, but I intentionally kept the changes to `RelayURL` limited to the functionality in this issue, because otherwise the changeset becomes very big and risky.
Issue reproduction
------------------
**Device:** iPhone 14 Pro simulator
**iOS:** 17.0
**Damus:** Local build from `476f52562` with the following local change:
``` diff
Signed-off-by: William Casarin <jb55@jb55.com>
Issue reproduction
------------------
**Device:** iPhone 14 Pro simulator
**iOS:** 17.0
**Damus:** `bb2eb904cc`
**Steps:**
1. Repost a note from another account (Account "B")
2. Mute user "B"
3. Check home page and your own profile page. Repost shows up with a muted box.
Fix
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
Summary
-------
This patch fixes the issue where the user might see notes from users that they have muted, if such note has been reposted or quoted.
Furthermore, this patch introduces some improvements on some of the associated views, making them more reusable.
Testing of the fix
------------------
**PASS**
**Device:** iPhone 14 Pro simulator
**iOS:** 17.0
**Damus:** This commit
**Test steps:**
1. Create two test accounts (if not created already). We will use test account "A". Test account "B" is an external test account
2. Make some notes from test account "B" (if non existent)
3. Switch to account "A"
4. Under test account "A", follow account "B"
5. Repost a note from account "B", and quote another note from account "B"
6. Access "account B"'s timeline. Repost and quoted note should all be visible. Layout should look as usual
7. Click on the reposted note. Should appear and it should look normal
8. Click on the note with the quote. Should appear and it should look normal
9. Click on the quoted note. Should appear and it should look normal
10. Now mute account "B"
12. Go back to account "A"'s timeline
13. Repost should appear, but the reposted content should be hidden behind a mute box. Clicking on show/hide should show or hide muted content
14. Note with quoted content should appear, but the quoted content should be hidden behind a mute box. Clicking on show/hide should work as expected
15. Make sure that the layout in steps 13 and 14 look good.
16. Click on the repost to access the thread view. Should be muted as expected.
17. Add a comment to the repost. Comment should appear even if the mute box hides the main note
18. Click on the note with quote to open its thread view. Comments should appear, main note should appear, but quoted content should be behind the mute box
19. Under account "B", add a comment to the quoted notes
20. Under account "A", check in the thread view that "B"'s reply is behind a mute box
21. Reply to the note with the quote. Check that the note appears correctly and that quoted content is behind the mute box (in the post composer view)
22. Find on Nostr a post where one of the replies contains a quoted note. Mute the user of the quoted content, and check that quoted content is now in a mute box
Smoke sanity test
-----------------
**PASS**
**Device:** iPhone 14 pro simulator
**iOS:** 16.4
**Test steps:** Browse a timeline filled with real notes and comments. Go through different notes and threads, mute some users, just to make sure nothing else appears obsviously broken.
Other notes
-----------
I removed this code:
```
.frame(maxWidth: .infinity, minHeight: PFP_SIZE)
```
from `EventShell`, because it was causing the layout to break on "threaded" style event view with muted quoted content (e.g. in a reply with quoted content).
The line of code dates back to `495859e07f`, but I am not sure why this line existed in the first place, or if removing it has any negative impact.
Closes: https://github.com/damus-io/damus/issues/1216
Changelog-Fixed: Hide quoted or reposted notes from people whom the user has muted. (#1216)
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
Testing
-------
**PASS**
**Device:** iPhone 14 Pro simulator
**iOS:** 17.0
**Damus:** This commit
**Steps:**
1. Setup accounts "A" and "B" that you control. Account "A" will be on our device under test.
2. Post something
3. Make a reply using Account A (Reply 1)
4. Make a reply using Account B (Reply 2)
5. Make another reply using account A (Reply 3)
6. Order of replies should be (top to bottom): 1, 2, 3
7. Mute user B
8. Order of replies should be: 1, 3, 2
Performance check
-----------------
**Device:** iPhone 14 Pro simulator
**iOS:** 17.0
**Damus:** This commit
**Steps:**
1. Locally change the code and add a print statement right before the sorting begins. In that print statement, include the number of events that will be sorted
2. Run Damus and go to a busy thread (I found one with 45 replies)
3. Go to the thread, and monitor the logs.
4. Navigate a bit between replies and monitor logs.
**Results:** I only saw a few print statements being printed with each navigation action, which indicates that we are not constantly re-sorting this object (which would be inefficient). Therefore, it seems like performance/efficiency would not be a problem.
Changelog-Changed: Show muted thread replies at the bottom of the thread view (#1522)
Closes: https://github.com/damus-io/damus/issues/1522
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
Device: iPhone 13 mini (Physical device)
iOS: iOS 17.0.1
Remarks: Some entitlements removed locally to be able to build to device without access to development certificate
Steps
-----
1. Go to the home timeline view.
2. Click on a profile on any post
3. Swipe back to the home timeline view (Do not press "back" button)
4. Click on that same profile again
5. Scroll down the profile
6. Make sure that toolbar looks good (Does not have a white background)
Results: Swiping back from profile does not cause any issues. View layout of the custom navbar looks good
Changelog-Fixed: Fix small graphical toolbar bug when scrolling profiles
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
On iOS 17.0, swiping back from a view that uses
`.navigationBarHidden(true)` caused the `NavigationStack` view to
freeze. This fixes the issue by creating a custom toolbar using
`.toolbar` instead.
Issue reproduction steps
------------------------
I found a very good clue to reproduce this issue from
[https://damus.io/note162rt4fctxepnj9cdtr9a82k7jtw3e33hj742ejly3q84tkwsfars4k9glr](https://damus.io/note162rt4fctxepnj9cdtr9a82k7jtw3e33hj742ejly3q84tkwsfars4k9glr)
**Device:** iPhone 13 mini (Physical device)
**iOS:** 17.0.1
**Damus:** 1.6 (18) 4377cf28ef
**Steps:**
1. Go to the home timeline view.
2. Click on a profile on any post
3. Swipe back to the home timeline view (Do not press "back" button)
4. Click on that same profile again
**Ideal behaviour:** On step 4, you should be taken to the profile view
**Actual behaviour:** The whole timeline view, top bar, etc seems to "freeze" and no longer respond.
Root causing investigation
--------------------------
I attempted various things until I could narrow it down. Here is a
summary of what I discovered:
1. First I attempted to investigate where the deadlock would live, by
analyzing the thread states in the debugger. However:
1. I did not find much differences between the thread states of a
normal app running and the app running after the issue
2. **I noticed that the tab bar at the bottom was still working, so
unless those views are running on different threads, it might not
have been a deadlock**
3. NostrDB ingested and writer threads seemed to be waiting on a
mutex most of the time I paused execution, but that also happened
under normal conditions
4. The crux of what made this difficult is that most of the UI
related threads were in assembly, which was harder to interpret.
However, the top of the stack in those threads were usually
`mach_msg_trap`, which I believe is just the debugger
interrupting execution. Below it, there were usually normal
assembly instructions being run, such as `mov` and `ldp`
instructions _(Move value and load a pair of registers)_, and
stepping through some of those seemed to move the program
counter. So I believe that the threads are running
5. Running `thread info` on some of the threads (e.g. main) revealed
that it seemed to be waiting on `mach_msg2_trap`, which again I
believe is just the debugger pausing execution.
2. **After some more testing, I realized that swiping back only breaks
when swiping back from the `ProfileView`, but not other views**
2. I tried to check if the issue was incorrect hashing of `Router`
objects: `NavigationStack` uses `NavigationPath`, which needs a
collection of hashable elements. I thought that if hashing was done
incorrectly, the NavigationStack might have issues managing views.
But that did not seem to be it either.
1. I tried experimenting with the hashing logic for the Profile
router. No changes
2. I tried purposefully messing up with the hashing logic of a good,
working view by adding random numbers into the hash. No issues on
swiping out of that view either.
3. That lead me to the possibility that the issue is within the
`ProfileView` body. I commented parts of the code out and tested each
portion of it in a binary search fashion, and narrowed it down a
specific line:
```
.navigationBarHidden(true)
```
Whenever I remove this line or set this to `false`, the freezing no
longer occurs. According to the Apple developer docs, this is
deprecated:
[https://developer.apple.com/documentation/swiftui/view/navigationbarhidden(_:)](https://developer.apple.com/documentation/swiftui/view/navigationbarhidden(_:))
I tried to replace it with its newer replacement: `.toolbar(.hidden,
for: .automatic)`, but that also causes the freeze.
So, just removing that line fixes the freeze, however it breaks the
layout by showing the unwanted back button.
Fix
---
I was able to fix it by implementing the custom toolbar under `.toolbar`
modifier, and hiding the back button (as opposed to the whole nav bar)
Testing of the fix
------------------
**PASS**
**Device:** iPhone 13 mini (Physical device)
**iOS:** iOS 17.0.1
**Damus:** This commit
**Special remarks:** Some entitlements removed locally to be able to
build to device without access to development certificate
**Test steps:** Same as reproduction steps
**Results:** Swiping back from profile does not cause any issues. View
layout of the custom navbar is unaltered in appearance.
iOS 16 smoke test
-----------------
**PASS**
**Device:** iPhone 14 Pro simulator
**iOS:** 16.4
**Damus:** This commit
**Special remarks:** Same as test above
**Test steps:** Same as reproduction steps. However here we are not
checking the freezing (as it was not reproducible in the simulator). We
are checking that the changes did not break navigation, nor layout, nor
caused any build issues.
**Results:** Working as expected
Closes: https://github.com/damus-io/damus/issues/1449
Changelog-Fixed: Fix UI freeze after swiping back from profile (#1449)
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
When users view who a certain person follows, now they will see an extra
tab to see the hashtags that they follow.
This new tab contains a list of followed hashtags, each of which
includes an option to follow/unfollow the hashtag, as well as the
ability to visit the hashtag timeline
Testing
**iOS:** 17.0 (iPhone 14 Pro Simulator)
**Damus:** (This commit)
**Test steps:**
1. Go to search view, search for a couple of hashtags: #apple, #orange, #kiwi
2. Go to the test accounts own profile via the drawer menu
3. Click on "Following". Make sure there are two tabs now.
4. Scroll down, switch tabs between "People" and "Hashtags". Make sure that scrolling and switching tabs work
5. Unfollow and follow a user. Make sure that this still works
6. Make sure that #apple, #orange, #kiwi hashtags are visible under the "Hashtags" tab
7. Unfollow "#kiwi". Check that the button label now switches from "Unfollow" to "Follow"
8. Click on "#kiwi". Make sure that it takes you to the page where posts with that hashtag appears
9. Go to @jb55's profile
10. Click on "Following"
11. Ensure that there is a "Hashtags" tab
12. Check that @jb55's followed hashtags are shown (not your own)
13. Follow one of the same hashtags as @jb55's
14. Go back to your own profile and go to your own following view again.
15. Make sure that this newly added tag is present on the list, and that #kiwi is not.
Closes: https://github.com/damus-io/damus/issues/606
Changelog-Added: Add followed hashtags to your following list
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
This commit adds a setting where the user can choose to hide notes with
a #nsfw hashtag. This setting was implemented to allow users to filter
out adult or other unsafe content.
I moved the code logic for content filtering into a new file, and
defined a protocol for content filters. Although the logic is still
simple, this might help in developing a flexible API in case we have
more complex filtering needs in the future.
I also modified the name of the "Appearance" setting to "Appearance and
filters", to make it easier for users to intuitively find this setting.
(Note: Re-translations of this string might be necessary)
**PASS**
**iOS:**
- iOS 17.0 (iPhone 14 Pro)
**Damus:** (This commit)
**Steps:**
1. Follow another account that you control (Account B)
2. On account B, post a note saying "#test this is a test". This note should show up on the home feed.
3. On account B, post a note saying "#nsfw this is a test". This note should NOT show up on the home feed
4. Go to settings and disable the NSFW filter. Go back to the home view. The #nsfw post should now show up.
5. Close app and reopen. NSFW post should still show up (i.e. Setting should be persistent)
6. Unfollow account B
7. Close app and reopen.
8. Follow the "#grownostr" hashtag
9. Turn on the NSFW filter
10. On account B, post a note saying "#grownostr this is a test". This note should show up on the home view.
11. On account B, post a note saying "#grownostr #nsfw this is a test". This note should NOT show up.
12. Double-check the "notes and replies" tab. Note should NOT show up there either.
12. Turn off NSFW filter
13. Note from step 11 should now show up.
14. Go to Universe view and find a post with a hashtag. Remember where the post is.
14. Locally change the tag keyword from "nsfw" to that hashtag (Note: I had to test this way because my posts were not showing up in the Universe view)
15. Turn off the filter. Check post is there, in the Universe view.
16. Turn on the filter. Check post is no longer there in the Universe view. (Check the neighboring posts are the same, to make sure)
17. Bring back the code to its normal state.
18. Search for "#nsfw". Make sure that #nsfw appears (I believe this is ok, because it means the person is purposefully searching for it)
Closes: https://github.com/damus-io/damus/issues/1412
Changelog-Added: Add "Do not show #nsfw tagged posts" setting
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
Changelog-Fixed: Fix compilation error on test target in UserSearchCacheTests
Signed-off-by: Daniel D‘Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>