Reverting due to CI error:
```
damus file:///Volumes/workspace/repository/damus/cs.lproj/Localizable.stringsdict
validation failed: Couldn't parse property list because the input data
was in an invalid format (1)
```
This reverts commit fa738c4303, reversing
changes made to 9511ba767a.
034f31797e Translate Localizable.strings in de
adb6f66a4f Translate Localizable.strings in zh_TW
a5f438b9c7 Translate Localizable.strings in zh_HK
d7f04d9ab9 Translate Localizable.strings in zh_HK
0b2ea46ef4 Translate Localizable.strings in zh_HK
331ed96d57 Translate Localizable.strings in zh_CN
701a747ed6 Translate Localizable.strings in cs
118c2bf2b2 Translate Localizable.stringsdict in cs
7a4f82c97b Translate Localizable.strings in de
d1e3a06cc6 Translate Localizable.strings in de
b9d960b54b Translate InfoPlist.strings in cs
* branch `translations` of https://github.com/damus-io/damus:
Translate Localizable.strings in de
Translate Localizable.strings in zh_TW
Translate Localizable.strings in zh_HK
Translate Localizable.strings in zh_HK
Translate Localizable.strings in zh_HK
Translate Localizable.strings in zh_CN
Translate Localizable.strings in cs
Translate Localizable.stringsdict in cs
Translate Localizable.strings in de
Translate Localizable.strings in de
Translate InfoPlist.strings in cs
Nothing has changed, but we need to submit a new minor version with
the subscription products since we missed those in the 1.7 appstore
release.
Signed-off-by: William Casarin <jb55@jb55.com>
Modify EditPictureControl to use the CameraController exactly as
PostView does.
Lightning-address: kernelkind@getalby.com
Signed-off-by: kernelkind <kernelkind@gmail.com>
Link: 20240228033235.66935-3-kernelkind@gmail.com
Signed-off-by: William Casarin <jb55@jb55.com>
- Use jpeg instead of png data when processing a UIImage.
- Make processing of media occur after user confirms upload selection when possible for better responsiveness.
- Reduce redundant data fetching.
Lightning-address: kernelkind@getalby.com
Signed-off-by: kernelkind <kernelkind@gmail.com>
Link: 20240228033235.66935-2-kernelkind@gmail.com
Signed-off-by: William Casarin <jb55@jb55.com>
This should not be visible to end-users on normal circumstances, but we
should regardless show an error message if something goes wrong with the
IAP receipt verification, to prompt them to contact support.
Testing
-------
PASS
Device: iPhone simulator
iOS: 17.2
Damus: This commit
damus-api: d3801376fa204433661be6de8b7974f12b0ad25f
Setup:
- Local Testing server
- Xcode StoreKit environment
Steps:
1. Set MOCK_VERIFY to false on the server (that means receipt verification will fail on Xcode environment)
2. Try to make IAP purchase. Error should appear on UI
3. Set MOCK_VERIFY to true on the server and restart StoreKit environment (Receipt validation will always work)
5. Try to make IAP purchase. Onboarding flow should go as normal with no error messages. PASS
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit changes when the Damus Purple onboarding gets triggered. Now
it only shows the onboarding if it is the first time they are purchasing
Damus Purple for a Nostr account. If it is not the first they see the
onboarding, they are directed to a sheet that displays their new account
info (e.g. a renewal)
However, if the website links to `damus:purple:welcome` links, the app
will still show the onboarding. This will be addressed on the
website-side by taking them to `damus:purple:landing` instead when it is
a renewal.
Testing
---------
PASS
Device: iPhone 13 mini (Physical device)
iOS: 17.3.1
Damus: This commit
damus-api: d3801376fa204433661be6de8b7974f12b0ad25f
damus-website: 6bb425e324c318ca474417cbd2b2f8bb74f9505f
Setup:
- iOS configured to use a local test environment
- Local damus-api server and local damus-website server setup and properly configured
- Fresh db (i.e. Delete mdb files before starting)
Coverage:
1. LN flow with switching to the app instead of clicking "continue". PASS
a. Ensure that first purchase will result in onboarding being shown. PASS
b. Ensure that second purchase will result in onboarding NOT being shown (User should be taken to the account info screen). PASS
c. Restart app completely. Ensure third purchase will result in onboarding NOT being shown (only account info screen). PASS
2. LN flow with clicking continue (Since website changes are not ready, we will simulate them by manually generally appropriate "continue" URL QR codes)
a. Note: Clear DB again before starting this portion, and completely restart app.
b. Ensure that first purchase will result in onboarding being shown. PASS
c. Ensure that second purchase (with continue URL manually hard-coded to `damus:purple:landing`) results in account info being shown with updated info. PASS
d. Restart app completely and repeat test 2(c). PASS
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit adds Damus Purple expiry notification support.
How it works: Whenever the app initiates or enters the foreground, it
checks the user's account expiry, and calculates what notifications to
display (It is functional, not imperative, to better match how
the notifications view works)
The notification handlers work the same as every other notification
handler for Nostr events. However, local iOS notifications were not
implemented to maintain these reminders more discreet.
Current limitations:
- Notifications cannot be dismissed
- Notifications are dismissed only when Damus Purple is extended
- After making a purchase, notifications are not dismissed right away
- Bell icon with purple badge shows up on every app restart if user's account is expired
Testing
-------
Device: iPhone 13 Mini
iOS: 17.3.1
Damus: This commit
damus-api: d3801376fa204433661be6de8b7974f12b0ad25f
Setup:
- Local servers Setup
- Debug endpoints enabled for changing expiry date on the fly
Coverage:
1. Expired account
1. Starting the app on home screen shows bell icon with purple badge. PASS
2. 4 notifications appear on notifications view (7,3,1,0 days to expiry). PASS
3. Notifications appear in correct chronological order. PASS
4. Notifications look consistent in appearance. PASS
5. Expiry notifications' text size follows text size settings. PASS
6. Clicking on notification CTA takes user to account info page. PASS
2. Non-expired account (set expiry, restart app)
1. No expiry notifications, no bell icon. PASS
3. Expiry in 6 days (set expiry, restart app)
1. Starting the app on home screen shows bell icon with purple badge. PASS
2. Starting the app on the notification screen renders notifications the same way. PASS
3. Only one notification (7 days remaining) appears. PASS
4. Expiry in 2 days. PASS
5. General
1. Clicking bell icon clears away "new notifications" badge. PASS
2. Performance of notifications view does not seem affected. PASS
3. Performance of app on startup does not seem affected. PASS
6. IAP
1. Active IAP + expiry date in 2 days does not trigger reminder notification (Because it is auto-renewed). PASS
Closes: https://github.com/damus-io/damus/issues/1973
Changelog-Added: Notification reminders for Damus Purple impending expiration
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This merge adds a bunch of new features from charlie's work on the new
mutelist changes:
- Muted words
- Mute performance optimizations
- New mute list UI
I needed to make a few changes to fix the tests in this merge. Otherwise
it seems to work ok!
Thank to Charlie for getting all of this working after many rounds of
review!
* branch `mute` of https://github.com/damus-io/damus:
mute: fix bug with duplicate Indefinite items in MuteDurationMenu
mute: fix mute hashtag from search view if no existing mutelist
mute: integrate new MutelistManager
mute: adding MutelistManager.swift
mute: add maybe_get_content function to NdbNote
mute: fix bug where mutes can't be added without existing mutelist
mute: fix issue with not being able to change mute duration
mute: don't mutate string when adding hashtag
mute: implement fast MuteItem decoder
tags: add u64 decoding function
mute: migrating muted_threads to new mute list
mute: adding ability to mute hashtag from SearchView
mute: updating UI to support new mute list
mute: adding filtering support for MuteItem events
mute: receiving New Mute List Type
mute: migrate Lists.swift to use new MuteItem
mute: add new UI views for new mute list
mute: adding new structs/enums for new mute list
Changelog-Added: Add ability to mute words, add new mutelist interface (Charlie)
The `Indefinite` was added to DamusDuration in "Fixing issue with not
being able to change mute duration” so this needs to be removed so that
there isn’t a repeative item in the menu.
Lighting-Address: fishcharlie@strike.me
Signed-off-by: Charlie Fish <contact@charlie.fish>
Reviewed-by: William Casarin <jb55@jb55.com>
Link: 20240210163650.42884-6-contact@charlie.fish
Signed-off-by: William Casarin <jb55@jb55.com>
There is a bug where if a user creates a new account and tries to mute a
hashtag from the search view it will fail silently. This is due to the
fact that the user has no existing mutelist.
Lighting-Address: fishcharlie@strike.me
Signed-off-by: Charlie Fish <contact@charlie.fish>
Reviewed-by: William Casarin <jb55@jb55.com>
Link: 20240210163650.42884-5-contact@charlie.fish
Signed-off-by: William Casarin <jb55@jb55.com>
This patch is slightly large (I think still within the guidelines tho) ,
but also pretty straightforward. I thought for a while about how I could
split this up in a straightforward way, and I couldn’t come up with
anything without breaking intermediate builds.
- Deleted a lot of old/unnecessary code (ie. the Collection extension
for MuteItem, since we’re now using the MutelistManager sets)
- Changed damus_state.contacts to damus_state.mutelist_manager for all
mute list manager work
- Updated MutelistView to take advantage of new code (this is probably
the largest change in this patch)
Lighting-Address: fishcharlie@strike.me
Signed-off-by: Charlie Fish <contact@charlie.fish>
Reviewed-by: William Casarin <jb55@jb55.com>
Link: 20240210163650.42884-4-contact@charlie.fish
Signed-off-by: William Casarin <jb55@jb55.com>
This patch adds MutelistManager which contains separate sets for each
type of muted item.
Whenever we receive a new event we parse it into those sets.
When checking to see if an event is muted, we simply check in each of
those sets if it contains the given mute. For words/phrases we have to
loop through each item in the set to see if the event contains the given
word.
In future patches I will be implementing and integrating this new
MutelistManager.
Lighting-Address: fishcharlie@strike.me
Signed-off-by: Charlie Fish <contact@charlie.fish>
Reviewed-by: William Casarin <jb55@jb55.com>
Link: 20240210163650.42884-3-contact@charlie.fish
Signed-off-by: William Casarin <jb55@jb55.com>
This patch adds a maybe_get_content method to NdbNote which returns an
optional string instead of “*failed to decrypt content*” on DM
decryption failure.
This method will be used by the MutelistManager in future patches.
Lighting-Address: fishcharlie@strike.me
Signed-off-by: Charlie Fish <contact@charlie.fish>
Reviewed-by: William Casarin <jb55@jb55.com>
Link: 20240210163650.42884-2-contact@charlie.fish
Signed-off-by: William Casarin <jb55@jb55.com>
Automatically show welcome sheet for people who completed a Lightning
checkout but did not click on the "Continue" button
Some people get confused in the last step of the lightning checkout and
they do not click on the "Continue in app", which causes the welcome
screen to not show up and the translation setting to not be setup.
This ticket addresses this issue to ensure they get the welcome screen
in such cases.
This is how it works:
- When they go through the mandatory checkout verification step, the
verify screen registers that there is a checkout in progress (and
which checkout is in progress) on the DamusPurple struct
- Every time the app enters the foreground, it checks for that flag:
- If there are no checkouts in progress, it does nothing
- If there is one or multiple checkouts in progress, it checks the
checkout status for those. If any checkout is freshly completed and
successful, and the account is now active, it shows the welcome
screen and onboarding
- Once the welcome screen is shown, those checkouts are marked
internally as handled (so that we only show it once)
===========
Testing
===========
PASS
Damus: This commit
Device: iPhone 13 Mini (real physical device)
iOS: 17.3.1
damus-api: 044150fedddc5ba4135a80579e41e9c1c5743fc0
damus-website: af8089128159e25df31141be624b4090c66d6ddf
Setup:
- Local test Setup
- Clean db before starting
PART 1: LN flow without clicking on the link
---------------------------------------------
Steps:
1. Go through the normal LN flow, EXCEPT at the last step. On the last
step, instead of clicking "continue in the app", just switch to the
app.
2. Ensure the welcome screen and onboarding shows up, and the purple
screen updates to show account info. PASS
3. Switch out and into the app again. Welcome screen should NOT show up
again. PASS
4. Close the app completely and open the app again. Purple welcome
screen should NOT show up again. PASS
PART 2: Normal LN flow
---------------------------------------------
Steps:
1. Reset the entire test setup
2. Go through the normal LN flow (this time click on "continue in app").
The welcome screen should show up without issues or glitches. PASS
PART 3: Crazy flow with multiple incomplete checkouts
---------------------------------------------
(This is to simulate a confused user who accidentally opens multiple new
checkouts, but in the end only completes one of them)
Steps:
1. Reset the entire test setup
2. Open 5 LN checkouts and verify npub with all of them.
3. Only pay one of those checkouts (to make it more confusing, don't pay
the first or last one, but a random one in between)
4. Go to the app directly (Do not use the link, just go directly to the app)
Related: https://github.com/damus-io/damus/issues/1892
Changelog-Fixed: Fix welcome screen not showing if the user enters the app directly after a successful checkout without going through the link
Closes: https://github.com/damus-io/damus/issues/2021
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Link: 20240223212945.37384-2-daniel@daquino.me
Signed-off-by: William Casarin <jb55@jb55.com>
Apple In-app purchases do not respond immediately. This commit adds a
loading spinner element, to improve the UX and avoid the appearance of a
broken/unresponsive element.
Testing
--------
Device: iPhone 15 simulator
iOS: 17.2
Damus: This commit
Setup:
- Using the sandbox environment
- No tx to start with
- IAP experimental support enabled on developer settings in Damus
Steps:
1. Click "purchase" in any option on the damus purple screen
2. It should show a loading spinner while the purchase action is loading. PASS
3. On the confirmation screen, cancel the purchase.
4. Purchase buttons should show again. PASS
Closes: https://github.com/damus-io/damus/issues/2020
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Link: 20240223212945.37384-1-daniel@daquino.me
Signed-off-by: William Casarin <jb55@jb55.com>
Uploaded gifs now upload as gifs again instead of still images.
Fixes: 904ae6c24d ("Fix gif upload as still images")
Lightning-address: kernelkind@getalby.com
Signed-off-by: kernelkind <kernelkind@gmail.com>
Reviewed-by: William Casarin <jb55@jb55.com>
Link: 20240220234818.27472-1-kernelkind@gmail.com
Signed-off-by: William Casarin <jb55@jb55.com>
When auto-translate is enabled, translations are saved in cache through
preload_event in EventCache so it's redundant and wasteful to call
translate() as an async task
Closes: https://github.com/damus-io/damus/issues/1940
Lightning-address: kernelkind@getalby.com
Signed-off-by: kernelkind <kernelkind@gmail.com>
Signed-off-by: William Casarin <jb55@jb55.com>
The responsibility of MediaPicker is to 'pick' all sorts of media, not
just images.
Lightning-address: kernelkind@getalby.com
Signed-off-by: kernelkind <kernelkind@gmail.com>
Signed-off-by: William Casarin <jb55@jb55.com>
Images selected from the photo library will automatically have their
gps data stripped regardless of whether the user toggles the 'Location'
button in the system level photo library view.
Changelog-Changed: Always strip GPS data from images
Closes: https://github.com/damus-io/damus/issues/1990
Lightning-address: kernelkind@getalby.com
Signed-off-by: kernelkind <kernelkind@gmail.com>
Signed-off-by: William Casarin <jb55@jb55.com>
Upgrade the ImagePicker to use PHPickerViewController instead of
UIImagePickerController for the photo library since the
PHPickerViewController allows for more options for how the user
shares their media, such as whether location data should be
included.
Create a CameraController since PHPickerViewController is only used for
the photo library. After capturing media with the camera, it will be
saved to the user's photo library and the photo library view will
appear for the user to select the media they captured. The user can then
toggle whether they would like apple to strip their media of location
data before handing it off to Damus.
Lightning-address: kernelkind@getalby.com
Signed-off-by: kernelkind <kernelkind@gmail.com>
Signed-off-by: William Casarin <jb55@jb55.com>
Add a function to strip GPS data from images before uploading to
hosting service.
Lightning-address: kernelkind@getalby.com
Signed-off-by: kernelkind <kernelkind@gmail.com>
Signed-off-by: William Casarin <jb55@jb55.com>
This patch adds a new ProxyView which is added to the Event Shell
whenever an event has the proxy tag. It includes images of the protocol
logos that are listed in the NIP docs.
Reviewed-by: William Casarin <jb55@jb55>.com
Link: 20240205032400.7069-1-ericholguin@apache.org
Signed-off-by: William Casarin <jb55@jb55.com>
This commit adapts the functionality around login/logout with relation
to Damus Purple In-App purchases (IAP). Due to (apparent) limitations on
Renewable subscription In-app purchases (It seems that there can only be
one active IAP subscription per device or Apple ID), these changes add
support for only one IAP subscription at a time.
To prevent confusion, a customer who logs out and logs into a separate
account will see a message indicating the limitation. Any other Nostr
account won't be able to manage IAP on a device that contains an IAP
registered to a different user.
To make this feature possible, the following changes were made to the
code:
1. IAP purchases are now associated with an account UUID. This account
UUID is generated by the server. Each npub gets one and only one UUID
for this purpose.
2. This UUID is used to determine which npub owns the IAP on the device.
It is used as the source of truth when determining whether a
particular Purple account is manageable on a device or not
3. `DamusPurple` was changed to adhere to a new IAP flow API design
changes. Previously, the client would create an (inactive) account,
and then send the IAP receipt to the server for activation. Now, the
client fetches the npub's UUID from the server, associates it with an
IAP during purchase, and sends the IAP receipt to the server. The
server will then bump the expiry (if it's a renewal) or create a new
active account (if it's the first time).
4. Several changes were made to the StoreKit handling code to improve
handling:
a. The `DamusPurple.StoreKitManager` class now records all purchased
product updates, and sends them to the delegate each time the
delegate is updated. This helps ensure we do not miss purchased
product updates regardless of when and if `DamusPurpleView` is ever
instantiated.
b. `DamusPurple.StoreKitManager` is now used by `DamusPurple` in a
singleton pattern via `DamusPurple.StoreKitManager.standard`. This
helps maintain the local purchase history consistent (and avoid
losing such data) after `DamusState` or its `DamusPurple` are
destroyed and re-initialized.
c. Added logs (using the logger) to help us debug/troubleshoot
problems in the future
5. Changed the views around DamusPurple, to only show IAP
purchase/management options if applicable to a particular account. It
also shows instructive messages in other scenarios.
Testing
-------
damus: This commit
damus-api: d3956ee004a358a39c8570fdbd481d2f5f6f94ab
Device: iPhone 15 simulator
iOS: 17.2
Setup:
- Xcode (local) StoreKit environment
- All StoreKit transactions deleted before starting
- Running `damus` app target (which contains test StoreKit products)
- Local damus-api server running with `npm run dev` and
`MOCK_VERIFY=true` to disable real receipt verification
- Damus setup with experimental IAP support enabled, and Purple
environment set to "Test (local)" (localhost)
- Two `nsecs` readily available for account switching
- Clean DB (Delete db files before starting)
Steps:
1. Open the app and sign in to the first account
2. Go to Damus Purple screen. Marketing screen with buttons to purchase
products should be visible. PASS
3. Buy a product and monitor server logs as well as the screen.
a. IAP confirmation dialog should appear. PASS
b. After confirmation, server logs should show a receipt was sent
IMMEDIATELY and the response should be an HTTP 200. PASS
c. The welcome and onboarding screens should appear as normal. PASS
d. Once the onboarding sheet goes away, the Purple screen should now
show the account information. PASS
e. The account information should be correct. PASS
f. Under the account information, there should be a "manage" button. PASS
4. Click on "manage" and verify that the iOS subscription management
screen appears. PASS
5. Now log out and sign in to the second account
6. Go to Damus Purple screen.
a. Marketing screen should be visible. PASS
b. There should be no purchase buttons. instead, there should be a
message indicating that there can only be one active subscription
at a time, and that the app is unable to manage subscription for
this second acocunt. PASS
7. Log out and sign in to the first account. Go to the Purple screen.
a. Account info with the manage button should be visible like before. PASS
8. Through Xcode, delete transactions, and restart the app. This will
simulate the case where the user bought the subscription externally.
9. Go to the Purple screen.
a. Account info should be visible and correct. PASS
b. Below the account info, there should be a small note telling the
user to visit the website to manage their billing. PASS
Closes: https://github.com/damus-io/damus/issues/1815
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 moves most of StoreKit-specific logic that was embedded into
DamusPurpleView and places it into a new PurpleStoreKitManager struct,
to make code more reusable and readable by separating view concerns from
StoreKit-specific concerns.
Most of the code here should be in feature parity with the previous
behavior. However, a few logical improvements were made alongside this
refactoring:
- Improved StoreKit transaction update monitoring logic: Previously the
view would stop listening for purchase updates after the first update.
However, I made the program continuously listen for purchase updates,
as recommended by Apple's documentation
(https://developer.apple.com/documentation/storekit/transaction/3851206-updates)
- Improved/simplified logic around getting extra information from the
products: Information and the handling of product information was
spread in a few separate places. I incorporated those bits of
information into central and uniform interfaces on DamusPurpleType, to
simplify logic and future changes.
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 refactoring commit splits several view blocks from DamusPurpleView
into separate files.
- New view structs were defined within the DamusPurpleView namespace, to
avoid polluting the global namespace
- No logical changes were made. The functionality should have stayed
equivalent
- Changes were made conservatively, and as semantically as possible, to
make the code easier to work with.
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
This refactoring commit moves primitive, low complexity, helper views
from DamusPurpleView into a separate file, to reduce complexity on
DamusPurpleView.swift.
Although functions were changed into View structs, no logical changes
were made. (New version is functionally equivalent)
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 purely non-functional refactor of DamusPurpleView consisting
only of code mark section comments, and re-ordering for better
organization and to facilitate further refactoring.
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>