Compare commits

...

455 Commits

Author SHA1 Message Date
eb889a7591 Optimize classify_url function
Changelog-Fixed: Optimized classify_url function
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-05-06 10:58:39 -04:00
c9696dd9c8 Add inline note rendering of invoices to pull up wallet selector sheet
Changelog-Added: Added inline note rendering of invoices to pull up wallet selector sheet
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-05-06 10:56:39 -04:00
212b4785fb Fix note rendering for those that contain previewable items or leading and trailing whitespaces
Changelog-Fixed: Fixed note rendering for those that contain previewable items or leading and trailing whitespaces
Closes: https://github.com/damus-io/damus/issues/2187
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-05-06 10:55:35 -04:00
SanjaySiddharth
54d6161acd Show additional information on top of blurred images
Changelog-Changed: Added additional information on top of blurred images
Closes: https://github.com/damus-io/damus/issues/2854
Signed-off-by: SanjaySiddharth <mjsanjaysiddharth1999@gmail.com>
2025-04-21 16:28:56 -07:00
Daniel D’Aquino
b1fd84fd75 Add safety reminder for higher balances
This commit adds a reminder to users who hold more than 100K sats in
their NWC wallet, reminding them to learn about self-custody.

Changelog-Added: Added safety reminder to wallets with higher balance
Closes: https://github.com/damus-io/damus/issues/2984
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-04-21 15:46:33 -07:00
Daniel D’Aquino
9dbdf7928a Add network connect call to extensions
This commit fixes a regression on the highlighter and share extensions,
which was caused by a change in the code's architecture, which required
the network manager to be initialized.

Fixes: 8d48f77d95138c93ed93989989fa930b61c2d6fb
Closes: https://github.com/damus-io/damus/issues/2955
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-04-21 15:29:46 -07:00
Daniel D’Aquino
67f0e3d296 Add disclaimer to Coinos button
Changelog-Changed: Added disclaimer to clarify that Coinos is a third-party service
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-04-21 12:23:31 -07:00
Daniel D’Aquino
e498418c2d Add one-click Coinos wallet setup
This commit implements a one-click Coinos wallet setup.

This was implemented using the Coinos API, and using account details
that are deterministically generated from the user's private key.

Closes: https://github.com/damus-io/damus/issues/2961
Changelog-Added: Added one-click Coinos wallet setup
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-04-21 12:23:31 -07:00
33150a42c5 Hide future notes from timeline
Changelog-Fixed: Hide future notes from timeline

Closes: https://github.com/damus-io/damus/issues/2949
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-04-18 16:29:12 -07:00
e7fe4ab9b4 Inverse hellthread_notifications_enabled to be hellthread_notifications_disabled and add hellthread_notifications_max_pubkeys setting
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-04-18 16:14:13 -07:00
c146bab08a Add notification setting to hide hellthreads
Changelog-Added: Add notification setting to hide hellthreads
Closes: https://github.com/damus-io/damus/issues/2943
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-04-18 16:14:13 -07:00
Daniel D’Aquino
d1cced8d54 Fetch NIP-65 relay lists from profile view
Changelog-Fixed: Fixed issue where profiles with a NIP-65 relay list would not display on Damus
Closes: https://github.com/damus-io/damus/issues/2120
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-04-16 11:48:52 -07:00
Daniel D’Aquino
8849b6105c Add First Aid tool to repair relay list
This adds a First aid tool to repair the NIP-65 relay list

Changelog-Added: Added separated first aid option for relay lists that does not need a contact list reset
Closes: https://github.com/damus-io/damus/issues/2120
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-04-16 11:48:52 -07:00
Daniel D’Aquino
3a0acfaba1 Implement NostrNetworkManager and UserRelayListManager
This commit implements a new layer called NostrNetworkManager,
responsible for managing interactions with the Nostr network, and
providing a higher level API that is easier and more secure to use for
the layer above it.

It also integrates it with the rest of the app, by moving RelayPool and PostBox
into NostrNetworkManager, along with all their usages.

Changelog-Added: Added NIP-65 relay list support
Changelog-Changed: Improved robustness of relay list handling
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-04-16 11:48:52 -07:00
Daniel D’Aquino
0ec2b05070 Implement safe interface for unowned NdbNotes
This commit introduces a new interface that makes it easier and safer to
handle unowned NostrDB notes, by leveraging new non-copyable and borrow
features from modern Swift.

Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-04-16 11:48:52 -07:00
Daniel D’Aquino
130bbfafb4 New async streaming interface from RelayPool
This defines a higher level and easier to use streaming interface from
RelayPool.

Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-04-16 11:48:52 -07:00
Daniel D’Aquino
ffc75772f9 NIP-65 relay list models and definitions
This commit adds the base models needed for the NIP-65 relay list support.

This introduces no user-facing changes.

Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-04-16 11:48:52 -07:00
Daniel D’Aquino
5b3fac70ed Organize RelayPool namespace
This is a non-functional refactor that organizes some classes and
structs used by RelayPool under the same namespace.

Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-04-16 11:48:52 -07:00
Daniel D’Aquino
53e3f6d86b Define protocol NostrEventConvertible
This adds a new protocol for classes that can be converted to and from a
NostrEvent.

Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-04-16 11:48:52 -07:00
Daniel D’Aquino
c28ab7a57c Renamed RelayInfo to LegacyKind3RelayRWConfiguration
This is a non-functional refactor that makes a struct name more
detailed.

Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-04-16 11:48:52 -07:00
Daniel D’Aquino
09ce3af11e Add some miscellaneous documentation
This commit adds some documentation to miscellaneous functions and
classes.

Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-04-16 11:48:52 -07:00
e42c09883a Replace deprecated usage of UIMenuController with UITextViewDelegate
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-04-14 19:11:30 -07:00
77e3924809 Fix some compiler warnings
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-04-14 19:11:30 -07:00
3511b1ee91 Fix quote notes to include missing q tag
Changelog-Fixed: Fix quote notes to include missing q tag

Closes: https://github.com/damus-io/damus/issues/2615
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-04-14 19:10:46 -07:00
78a62c8ef0 Clean up code in ProfileName.name_choice
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-04-14 18:38:51 -07:00
Daniel D’Aquino
8b96b9f4e6 Merge pull request #2973 from damus-io/translations
Translations
2025-04-14 18:35:34 -07:00
Daniel D’Aquino
649a857c3a Update Kingfisher to 8.3.1
Changelog-Changed: Updated image cache for better stability
Closes: https://github.com/damus-io/damus/issues/2899
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-04-14 17:56:23 -07:00
transifex-integration[bot]
cdae2c7558 Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2025-04-08 11:52:23 +00:00
transifex-integration[bot]
3639110c51 Translate Localizable.strings in nl
100% translated source file: 'Localizable.strings'
on 'nl'.
2025-04-08 08:39:51 +00:00
186668512e Export strings for translation
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-04-07 20:39:27 -04:00
f63666fae2 Add missing localized string comment
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-04-07 20:39:08 -04:00
transifex-integration[bot]
68d25059b1 Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2025-04-07 20:25:30 -04:00
transifex-integration[bot]
9aef6b7f5b Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2025-04-07 20:25:30 -04:00
transifex-integration[bot]
d2e712575f Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2025-04-07 20:25:30 -04:00
transifex-integration[bot]
bf9674e6e4 Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2025-04-07 20:25:30 -04:00
transifex-integration[bot]
4815390cbe Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2025-04-07 20:25:30 -04:00
transifex-integration[bot]
6ce903f1f6 Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2025-04-07 20:25:30 -04:00
transifex-integration[bot]
b2c91ffce4 Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2025-04-07 20:25:30 -04:00
transifex-integration[bot]
ae335b18bf Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2025-04-07 20:25:29 -04:00
transifex-integration[bot]
6391819fb2 Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2025-04-07 20:25:29 -04:00
transifex-integration[bot]
5d0e56b7c7 Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2025-04-07 20:25:29 -04:00
transifex-integration[bot]
50ccc7bd7f Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2025-04-07 20:25:29 -04:00
transifex-integration[bot]
b3a6bcf3b2 Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2025-04-07 20:25:29 -04:00
transifex-integration[bot]
38b2988bbe Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2025-04-07 20:25:29 -04:00
transifex-integration[bot]
446c541dcb Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2025-04-07 20:25:29 -04:00
transifex-integration[bot]
31fd48ee52 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2025-04-07 20:25:28 -04:00
b35cc33c32 Add Unicode 16 emoji reactions for iOS 18.4+ by upgrading EmojiPicker
Changelog-Added: Added Unicode 16 emoji reactions for iOS 18.4+ by upgrading EmojiPicker
Closes: https://github.com/damus-io/damus/issues/2915
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-03-29 11:40:47 -03:00
SanjaySiddharth
9510290c29 Fix bug that closes the side menu when copying npub
Changelog-Fixed: Fixed issue where the side menu would close when copying the npub
Closes: https://github.com/damus-io/damus/issues/2748
Signed-off-by: SanjaySiddharth <mjsanjaysiddharth1999@gmail.com>
2025-03-28 22:00:00 -03:00
Daniel D’Aquino
3b1238b9c7 Merge pull request #2936 from damus-io/translations
Translations
2025-03-28 21:53:33 -03:00
SanjaySiddharth
3bec23ecac Add search feature to the settings screen
Closes: https://github.com/damus-io/damus/issues/2838
Changelog-Added: Added a search interface to the settings screen
Signed-off-by: SanjaySiddharth <mjsanjaysiddharth1999@gmail.com>
2025-03-28 18:48:08 -03:00
transifex-integration[bot]
7b678228b6 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-03-25 06:29:51 +00:00
transifex-integration[bot]
b1292d4562 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-03-25 06:29:41 +00:00
transifex-integration[bot]
a62d782fe5 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-03-25 06:29:30 +00:00
transifex-integration[bot]
81b07eb339 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-03-25 06:29:17 +00:00
transifex-integration[bot]
02f88398b9 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-03-25 06:28:56 +00:00
transifex-integration[bot]
e80961cc09 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-03-25 06:28:48 +00:00
transifex-integration[bot]
bd7721dc26 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-03-25 06:28:36 +00:00
transifex-integration[bot]
6d974bf71c Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-03-25 06:28:25 +00:00
transifex-integration[bot]
aeeb817735 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-03-25 06:27:59 +00:00
transifex-integration[bot]
b5e7033958 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-03-25 06:27:39 +00:00
transifex-integration[bot]
bdc843f30f Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-03-25 06:27:31 +00:00
transifex-integration[bot]
a823fa8e14 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-03-25 06:27:16 +00:00
transifex-integration[bot]
9232386c15 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-03-25 06:27:09 +00:00
transifex-integration[bot]
3c1547718c Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-03-25 06:26:58 +00:00
transifex-integration[bot]
b67a7f3e9e Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-03-25 06:23:06 +00:00
transifex-integration[bot]
92850d4f64 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-03-25 06:22:59 +00:00
Daniel D’Aquino
6323eafd7e v1.13.1 changelog
Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-03-24 14:02:08 -03:00
Daniel D’Aquino
b8fe826b58 Improve syncing and performance of ThreadModel
This commit introduces two minor improvements:
1. It ensures better consistency between ThreadModel and EventCache
2. It avoids unnecessary recursion calls on `add_event`

Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-03-24 13:52:35 -03:00
Daniel D’Aquino
841c49238f Fix thread parent event loading regression
This fixes a regression where ThreadModel would no longer look at
NostrDB saved notes for parent events, causing some instability on
thread loading — especially in poor networking conditions.

This was fixed by adding a call that searches for parent events in
EventCache/NostrDB each time an event is added to the ThreadModel.

That `add_event` function is the ideal spot to place the call because it
is the only interface used for all information updates incoming to the
ThreadModel, including:
- anytime an event is loaded from the network into the thread model.
- when the ThreadModel is first initialized, with an initial event.

Fixes: 74d5bee1f6
Changelog-Fixed: Fixed an issue where threads would not load properly
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-03-24 13:52:35 -03:00
transifex-integration[bot]
7ab612e3d9 Translate Localizable.strings in hu_HU
100% translated source file: 'Localizable.strings'
on 'hu_HU'.
2025-03-23 18:13:22 +00:00
transifex-integration[bot]
6d8a27688f Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2025-03-23 16:34:49 +00:00
transifex-integration[bot]
765385319a Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2025-03-23 16:34:31 +00:00
transifex-integration[bot]
342c49a3e5 Translate Localizable.strings in nl
100% translated source file: 'Localizable.strings'
on 'nl'.
2025-03-23 10:48:13 +00:00
transifex-integration[bot]
25860e7bb2 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-03-23 05:06:23 +00:00
transifex-integration[bot]
6962f2b462 Translate InfoPlist.strings in fr
100% translated source file: 'InfoPlist.strings'
on 'fr'.
2025-03-22 21:44:17 +00:00
e48ce4c6c5 Export strings for translation
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-03-22 15:53:21 -04:00
1cb311cc2c Fix localization issues in TransactionsView
Fixes: 22f2aba969 ("Fix localization issues in TransactionsView")
Changelog-Fixed: Fix localization issues in TransactionsView
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-03-22 15:51:31 -04:00
transifex-integration[bot]
401846abe4 Translate Localizable.stringsdict in hu_HU
100% translated source file: 'Localizable.stringsdict'
on 'hu_HU'.
2025-03-22 14:50:14 -04:00
transifex-integration[bot]
16ef393350 Translate Localizable.strings in hu_HU
100% translated source file: 'Localizable.strings'
on 'hu_HU'.
2025-03-22 14:50:14 -04:00
transifex-integration[bot]
d5742f8e4c Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2025-03-22 14:50:14 -04:00
transifex-integration[bot]
319063f823 Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2025-03-22 14:50:14 -04:00
transifex-integration[bot]
5b13cf5634 Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2025-03-22 14:50:14 -04:00
transifex-integration[bot]
da10b908b3 Translate Localizable.stringsdict in pl_PL
100% translated source file: 'Localizable.stringsdict'
on 'pl_PL'.
2025-03-22 14:50:14 -04:00
transifex-integration[bot]
4568935bc5 Translate Localizable.stringsdict in pl_PL
100% translated source file: 'Localizable.stringsdict'
on 'pl_PL'.
2025-03-22 14:50:14 -04:00
transifex-integration[bot]
467404a55e Translate Localizable.stringsdict in pl_PL
100% translated source file: 'Localizable.stringsdict'
on 'pl_PL'.
2025-03-22 14:50:13 -04:00
transifex-integration[bot]
fcfe1e4558 Translate Localizable.stringsdict in pl_PL
100% translated source file: 'Localizable.stringsdict'
on 'pl_PL'.
2025-03-22 14:50:13 -04:00
transifex-integration[bot]
c9d87a1b9a Translate Localizable.stringsdict in pl_PL
100% translated source file: 'Localizable.stringsdict'
on 'pl_PL'.
2025-03-22 14:50:13 -04:00
transifex-integration[bot]
35ebf4dfc2 Translate Localizable.stringsdict in pl_PL
100% translated source file: 'Localizable.stringsdict'
on 'pl_PL'.
2025-03-22 14:50:13 -04:00
transifex-integration[bot]
bc3c256d22 Translate Localizable.stringsdict in pl_PL
100% translated source file: 'Localizable.stringsdict'
on 'pl_PL'.
2025-03-22 14:50:13 -04:00
transifex-integration[bot]
0e10e74496 Translate Localizable.stringsdict in pl_PL
100% translated source file: 'Localizable.stringsdict'
on 'pl_PL'.
2025-03-22 14:50:13 -04:00
transifex-integration[bot]
ebe9097f73 Translate Localizable.stringsdict in pl_PL
100% translated source file: 'Localizable.stringsdict'
on 'pl_PL'.
2025-03-22 14:50:13 -04:00
transifex-integration[bot]
d61a11b647 Translate Localizable.stringsdict in pl_PL
100% translated source file: 'Localizable.stringsdict'
on 'pl_PL'.
2025-03-22 14:50:13 -04:00
transifex-integration[bot]
d980cc1f8e Translate Localizable.stringsdict in pl_PL
100% translated source file: 'Localizable.stringsdict'
on 'pl_PL'.
2025-03-22 14:50:12 -04:00
transifex-integration[bot]
bd6056ce2e Translate Localizable.stringsdict in pl_PL
100% translated source file: 'Localizable.stringsdict'
on 'pl_PL'.
2025-03-22 14:50:12 -04:00
transifex-integration[bot]
cf48fda8d0 Translate Localizable.stringsdict in pl_PL
100% translated source file: 'Localizable.stringsdict'
on 'pl_PL'.
2025-03-22 14:50:12 -04:00
transifex-integration[bot]
dc344cd28c Translate Localizable.stringsdict in pl_PL
100% translated source file: 'Localizable.stringsdict'
on 'pl_PL'.
2025-03-22 14:50:12 -04:00
transifex-integration[bot]
358610575f Translate Localizable.stringsdict in pl_PL
100% translated source file: 'Localizable.stringsdict'
on 'pl_PL'.
2025-03-22 14:50:12 -04:00
transifex-integration[bot]
a7869fccbb Translate Localizable.stringsdict in pl_PL
100% translated source file: 'Localizable.stringsdict'
on 'pl_PL'.
2025-03-22 14:50:12 -04:00
transifex-integration[bot]
a50903f90a Translate Localizable.stringsdict in pl_PL
100% translated source file: 'Localizable.stringsdict'
on 'pl_PL'.
2025-03-22 14:50:12 -04:00
transifex-integration[bot]
9243705995 Translate Localizable.stringsdict in de
100% translated source file: 'Localizable.stringsdict'
on 'de'.
2025-03-22 14:50:12 -04:00
transifex-integration[bot]
db4dd9eee9 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2025-03-22 14:50:10 -04:00
ericholguin
22f2aba969 nwc: Wallet Redesign
This PR redesigns the NWC wallet view. A new view is added to introduce zaps to users. The set up wallet view is simplified, with new and existing wallet setup separated.
This also adds new NWC features such as getBalance and listTransactions allowing users to see their balance and previous transactions made.

Changelog-Added: Added view introducing users to Zaps
Changelog-Added: Added new wallet view with balance and transactions list
Changelog-Changed: Improved integration with Nostr Wallet Connect wallets
Closes: https://github.com/damus-io/damus/issues/2900

Signed-off-by: ericholguin <ericholguin@apache.org>
Co-Authored-By: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-03-19 18:00:00 -03:00
Daniel D’Aquino
98f2777fda Version bump to 1.14
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-03-17 11:05:43 -03:00
Daniel D’Aquino
102ce43216 v1.13 changelog
Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-03-17 10:58:12 -03:00
William Casarin
0c148c8a1f Merge Communication Notifications 2025-03-03 14:22:11 -08:00
William Casarin
3cccb2eb6b project: fix version yet again
we should always be using the inherited project version so that
everything is consistent

Signed-off-by: William Casarin <jb55@jb55.com>
2025-03-03 14:21:53 -08:00
William Casarin
af4949e26a Communication notifications
Signed-off-by: William Casarin <jb55@jb55.com>
2025-03-03 14:21:53 -08:00
Claude
5bb7e95624 chore: update Package.swift to Swift tools version 6.0 2025-03-03 12:52:56 -08:00
814bcf694f Change spaces to newlines in new posts to provide cleaner separation between text, uploaded media, and quoted notes
Changelog-Changed: Changed spaces to newlines in new posts to provide cleaner separation between text, uploaded media, and quoted notes
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-03-03 11:51:08 -08:00
Daniel D’Aquino
b0382c61b1 Merge pull request #2889 from damus-io/translations
Translations
2025-03-03 11:33:28 -08:00
e2650a8bfc Fix bug where profile view was showing more than just the notes and replies on the notes / notes & replies tabs
Changelog-Fixed: Fix bug where profile view was showing more than just the notes and replies on the notes / notes & replies tabs
Fixes: caa4bfe864 ("Fix bug where profile view was showing more than just the notes and replies on the notes / notes & replies tabs")
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-03-03 11:20:34 -08:00
transifex-integration[bot]
ac39a53b33 Translate Localizable.stringsdict in pt_PT
100% translated source file: 'Localizable.stringsdict'
on 'pt_PT'.
2025-03-02 15:18:22 +00:00
transifex-integration[bot]
fb356cdf0b Translate InfoPlist.strings in pt_PT
100% translated source file: 'InfoPlist.strings'
on 'pt_PT'.
2025-03-02 15:16:26 +00:00
transifex-integration[bot]
238e89ce16 Translate InfoPlist.strings in pt_PT
100% translated source file: 'InfoPlist.strings'
on 'pt_PT'.
2025-03-02 15:16:15 +00:00
transifex-integration[bot]
6e041c79f7 Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2025-03-02 15:14:24 +00:00
William Casarin
6ef4b60d14 test: disable broken tests
Signed-off-by: William Casarin <jb55@jb55.com>
2025-03-01 17:07:19 -08:00
transifex-integration[bot]
054bec2d9a Translate Localizable.strings in ja
100% translated source file: 'Localizable.strings'
on 'ja'.
2025-03-01 14:15:26 -05:00
transifex-integration[bot]
943a46a343 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2025-03-01 14:15:26 -05:00
transifex-integration[bot]
17381f6b94 Translate Localizable.stringsdict in de
100% translated source file: 'Localizable.stringsdict'
on 'de'.
2025-03-01 14:15:26 -05:00
transifex-integration[bot]
18c88de407 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2025-03-01 14:15:25 -05:00
transifex-integration[bot]
99d21fc89b Translate Localizable.strings in nl
100% translated source file: 'Localizable.strings'
on 'nl'.
2025-03-01 14:15:25 -05:00
transifex-integration[bot]
db5c86a0d1 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2025-03-01 14:15:25 -05:00
transifex-integration[bot]
736ec6fb9e Translate Localizable.stringsdict in de
100% translated source file: 'Localizable.stringsdict'
on 'de'.
2025-03-01 14:15:25 -05:00
transifex-integration[bot]
fa2327325a Translate Localizable.stringsdict in de
100% translated source file: 'Localizable.stringsdict'
on 'de'.
2025-03-01 14:15:25 -05:00
transifex-integration[bot]
4fdf048040 Translate Localizable.stringsdict in de
100% translated source file: 'Localizable.stringsdict'
on 'de'.
2025-03-01 14:15:25 -05:00
transifex-integration[bot]
273538bd36 Translate Localizable.stringsdict in de
100% translated source file: 'Localizable.stringsdict'
on 'de'.
2025-03-01 14:15:25 -05:00
transifex-integration[bot]
0980c8c040 Translate Localizable.stringsdict in nl
100% translated source file: 'Localizable.stringsdict'
on 'nl'.
2025-03-01 14:15:25 -05:00
transifex-integration[bot]
f0bfdeaa5a Translate Localizable.stringsdict in th
100% translated source file: 'Localizable.stringsdict'
on 'th'.
2025-03-01 14:15:25 -05:00
transifex-integration[bot]
ab7c5c18e3 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-03-01 14:15:24 -05:00
transifex-integration[bot]
6ae95ab5ec Translate Localizable.stringsdict in ja
100% translated source file: 'Localizable.stringsdict'
on 'ja'.
2025-03-01 14:15:24 -05:00
eec630b2b0 Export strings for translation
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-03-01 14:15:23 -05:00
William Casarin
2b3d86968d add todo for fixing q tags
Signed-off-by: William Casarin <jb55@jb55.com>
2025-02-28 09:44:29 -08:00
William Casarin
935a6cae7a Merge conversation tab and other updates from Terry
I've tested these and they seem to be working!

Terry Yiu (3):
      Fix reposts banner to be localizable
      Add Conversations tab to profiles
      Remove mystery tabs meant to fix tab switching bug that no longer exists
2025-02-25 12:48:34 -08:00
William Casarin
d4940d8386 prs: ensure PR always have a linked issue
This makes project management a bit nicer in linear

Signed-off-by: William Casarin <jb55@jb55.com>
2025-02-25 10:28:37 -08:00
71ec18f6c6 Remove mystery tabs meant to fix tab switching bug that no longer exists
Changelog-Removed: Removed mystery tabs meant to fix tab switching bug that no longer exists
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-02-25 09:21:36 -05:00
caa4bfe864 Add Conversations tab to profiles
Changelog-Added: Added Conversations tab to profiles
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-02-24 21:34:16 -05:00
a87ba73160 Fix reposts banner to be localizable
Changelog-Fixed: Fixed reposts banner to be localizable
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-02-24 14:52:53 -05:00
Daniel D’Aquino
4324b185fe Improve open action handling for notifications
Push notifications were not opened reliably. To improve robustness, the
following changes were introduced:
1. The notification opening logic was updated to become more similar to
   URL handling, in a way that uses better defined interfaces and
   functions that provide better result guarantees, by separating
   complex handling logic, and the side-effects/mutations that
   are made after computing the open action — instead of relying on a
   complex logic function that produces side-effects as a result, which
   obfuscates the actual behavior of the function.
2. The LoadableThreadView was expanded and renamed to
   LoadableNostrEventView, to reflect that it can also handle non-thread
   nostr events, such as DMs, which is a necessity for handling push
   notifications.
3. A new type of Notify object, the `QueueableNotify` was introduced, to
   address issues where the listener/handler is not instantiated at the
   time the app notifies that there is a push notification to be opened.
   This was implemented using async streams, which simplifies the usage
   of this down to a simple "for-in" loop.

Closes: https://github.com/damus-io/damus/issues/2825
Changelog-Fixed: Fixed issue where some push notifications would not open in the app and leave users confused
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-02-21 11:28:26 -08:00
Daniel D’Aquino
1ab9b30b85 Add development and testing tips
These were included to help other developers with testing or
development.

Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-02-21 11:28:26 -08:00
William Casarin
81cf6ad297 Merge remote-tracking branches 'pr/2863', 'pr/2864', 'pr/2865' and 'pr/2866'
Daniel D’Aquino (4):
      Reduce swipe sensitivity on thread chat view
      Fix issue where a NWC connection would not work unless restarting the app
      Implement developer feature to avoid distractions
      Fix issue where note persisted after note publication
2025-02-21 11:10:55 -08:00
William Casarin
1b3be3a13b Revert "Update EventMenu.swift"
should have tested this first lol

This reverts commit 3a2ce04d6b.
2025-02-21 11:07:47 -08:00
alltheseas
3a2ce04d6b Update EventMenu.swift
replaced deprecated noteID with neventID in EventMenu.swift. NoteID currently appears in bubble/context menu of each note (top right three dots ellipsis).
2025-02-21 08:45:55 -06:00
Daniel D’Aquino
981821a6bc Fix issue where note persisted after note publication
There is no changelog entry needed because drafts are still an
unreleased feature.

Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Closes: https://github.com/damus-io/damus/issues/2836
2025-02-19 20:21:49 -08:00
Daniel D’Aquino
98f83769bd Fix issue where a NWC connection would not work unless restarting the app
Changelog-Fixed: Fixed issue where app would need a restart for new NWC wallets to work
Closes: https://github.com/damus-io/damus/issues/2859
Closes: https://github.com/damus-io/damus/issues/1135
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-02-19 17:58:14 -08:00
Daniel D’Aquino
7684f53281 Implement developer feature to avoid distractions
This commit implements an optional developer feature to scramble text
and blur images to prevent distractions during development and testing.

It is not perfect (It breaks some mentions and rich text objects, and
does not scramble non-alphanumeric languages such as Japanese), but
good enough to avoid distractions while working on most features.

No changelog entry is needed because this is not meant for the final
user.

Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-02-19 17:39:21 -08:00
Daniel D’Aquino
15af686a58 Fix issue where a NWC connection would not work unless restarting the app
Changelog-Fixed: Fixed issue where app would need a restart for new NWC wallets to work
Closes: https://github.com/damus-io/damus/issues/2859
Closes: https://github.com/damus-io/damus/issues/1135
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-02-19 17:22:32 -08:00
Daniel D’Aquino
aad8f9e8d4 Reduce swipe sensitivity on thread chat view
Value determined experimentally.

Closes: https://github.com/damus-io/damus/issues/2743
Changelog-Fixed: Fixed overly sensitive horizontal swipe on thread chat view
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-02-17 17:22:02 -08:00
b2ee44c0ab Trim whitespaces from Lightning addresses
Changelog-Fixed: Trim whitespaces from Lightning addresses
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-02-17 16:43:32 -08:00
William Casarin
a696ac5084 Merge translations 2025-02-13 10:20:53 -08:00
William Casarin
28237c3a63 Merge release process 2025-02-13 10:19:01 -08:00
transifex-integration[bot]
1cae4640c0 Translate InfoPlist.strings in pl_PL
100% translated source file: 'InfoPlist.strings'
on 'pl_PL'.
2025-02-13 15:00:03 +00:00
transifex-integration[bot]
21a07d54cb Translate InfoPlist.strings in pl_PL
100% translated source file: 'InfoPlist.strings'
on 'pl_PL'.
2025-02-13 14:59:49 +00:00
transifex-integration[bot]
1efd07b852 Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2025-02-13 14:58:45 +00:00
transifex-integration[bot]
e5eb7d44a2 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-02-13 04:25:45 +00:00
William Casarin
ec9a89ee4d Merge Fix unwanted draft auto-scrolls
Daniel D’Aquino (1):
      Fix unwanted auto-scrolls related to draft saving mechanism
2025-02-12 15:47:44 -08:00
William Casarin
4741c2a3e8 reposts: add links to repost listing in timeline
Signed-off-by: William Casarin <jb55@jb55.com>
2025-02-12 15:43:19 -08:00
Daniel D’Aquino
0111c5e2dc Fix unwanted auto-scrolls related to draft saving mechanism
This commit fixes an issue where the post view would scroll to the text
cursor at seemingly random times.

This was done by detaching the save view and its logic, so that we have
3 components:
1. The `PostView`
2. An auto-save view model (which is an Observable object)
3. A separate SwiftUI view for the auto-save indicator

The auto-save view model is shared between the `PostView` and the new
indicator view to ensure proper signaling and communication across
views.

However, this view model is only observed by the indicator view,
ensuring it updates its own view, while not causing any re-renders on
the rest of the `PostView`.

This refactor had the side-effect of making the auto-save logic and view
more reusable. It is now a separate collection of elements that can be
used anywhere else.

Beyond the scroll issue, this commit also prevents empty drafts from
being saved, by introducing the new save state called `.nothingToSave`

Note: No changelog item is needed because the new drafts feature was never
publicly released.

Changelog-None
Closes: https://github.com/damus-io/damus/issues/2826
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-02-12 13:28:40 -08:00
William Casarin
bed4e00b53 home: dont show reposts for the same note more than once
Fixes: https://github.com/damus-io/damus/issues/859
Changelog-Changed: Don't show reposts for the same note more than once in your home feed
Signed-off-by: William Casarin <jb55@jb55.com>
2025-02-12 12:19:10 -08:00
William Casarin
bf14d7138a driveby compile warning fixes
Signed-off-by: William Casarin <jb55@jb55.com>
2025-02-12 12:19:10 -08:00
emir yorulmaz
0c5da08a42 Change 'twitter' to 'X/Twitter' on README.md 2025-02-12 11:07:47 -08:00
Daniel D’Aquino
a6e123e928 Remove rust-nostr dependency
This commit removes rust-nostr dependency, and replaces the NIP-44 logic
with a new NIP-44 module based on the Swift NostrSDK implementation.

The decision to move away from rust-nostr and the Swift NostrSDK was
made for the following reasons:
1. `rust-nostr` caused the app size to double
2. We only need NIP44 functionality, and we don't need to bring
   everything else
3. The Swift NostrSDK caused conflicts around the secp256k1 dependency
   that is hard to address
4. The way we do things in the codebase is far different from the Swift
   NostrSDK, and we optimize it for use with NostrDB. Bringing it an
   outside library causes significant complexity in integration with
   NostrDB, and would effectively cause the codebase to be split into
   two different ways of achieving the same results. Therefore it is
   cleaner if we stick to our own Nostr structures and functions and
   focus on maintaining them.

However, the library CryptoSwift was added as a dependency, to bring in
ChaCha20 which is not supported by CryptoKit (CryptoKit supports the
ChaCha20-Poly1305 cipher, but NIP-44 uses ChaCha20 with HMAC-SHA256
instead)

Closes: https://github.com/damus-io/damus/issues/2849
Changelog-Changed: Made internal changes to reduce the app binary size
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-02-12 11:05:58 -08:00
transifex-integration[bot]
69b1173e08 Translate InfoPlist.strings in th
100% translated source file: 'InfoPlist.strings'
on 'th'.
2025-02-12 13:03:12 +00:00
transifex-integration[bot]
c3326213e9 Translate InfoPlist.strings in ja
100% translated source file: 'InfoPlist.strings'
on 'ja'.
2025-02-12 01:49:52 +00:00
325109d7b8 Remove preview strings from translation and add missing period to duplicate string to avoid double translation
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-02-11 09:52:03 -05:00
transifex-integration[bot]
f16d76605b Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2025-02-11 09:52:03 -05:00
transifex-integration[bot]
3eee1b205a Translate InfoPlist.strings in de
100% translated source file: 'InfoPlist.strings'
on 'de'.
2025-02-11 09:52:03 -05:00
transifex-integration[bot]
9545c6446d Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2025-02-11 09:52:03 -05:00
transifex-integration[bot]
40a75f65ab Translate Localizable.strings in nl
100% translated source file: 'Localizable.strings'
on 'nl'.
2025-02-11 09:52:03 -05:00
transifex-integration[bot]
98f42c9896 Translate InfoPlist.strings in nl
100% translated source file: 'InfoPlist.strings'
on 'nl'.
2025-02-11 09:52:03 -05:00
transifex-integration[bot]
5c22989675 Translate InfoPlist.strings in nl
100% translated source file: 'InfoPlist.strings'
on 'nl'.
2025-02-11 09:52:03 -05:00
999f16f6a4 Export strings for translation
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-02-11 09:51:56 -05:00
transifex-integration[bot]
3f5fd6eee8 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-02-10 18:35:32 -05:00
transifex-integration[bot]
7c195aa75c Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-02-10 18:35:32 -05:00
transifex-integration[bot]
2071efc129 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-02-10 18:35:32 -05:00
transifex-integration[bot]
9db2e9b464 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-02-10 18:35:31 -05:00
transifex-integration[bot]
5f6cb568ff Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-02-10 18:35:31 -05:00
transifex-integration[bot]
045399a065 Translate Localizable.stringsdict in th
100% translated source file: 'Localizable.stringsdict'
on 'th'.
2025-02-10 18:35:31 -05:00
transifex-integration[bot]
1b526143d0 Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2025-02-10 18:35:31 -05:00
transifex-integration[bot]
8a046c0d1b Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2025-02-10 18:35:31 -05:00
transifex-integration[bot]
2893e4234d Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2025-02-10 18:35:31 -05:00
transifex-integration[bot]
973a5ce2cb Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2025-02-10 18:35:31 -05:00
transifex-integration[bot]
1e81e90341 Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2025-02-10 18:35:30 -05:00
9e7943e0e9 Fix translation export script by upgrading nostr-sdk-swift dependency to support Mac Catalyst
Changelog-Fixed: Fixed translation export script by upgrading nostr-sdk-swift dependency to support Mac Catalyst
Closes: https://github.com/damus-io/damus/issues/2841
Fixes: 24c3e61a4b ("Fix translation export script")
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-02-10 15:09:35 -08:00
Daniel D’Aquino
bb7ac4fea5 Release notes for v1.12.3
Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-02-07 11:15:11 -08:00
Daniel D’Aquino
05d0e15359 Add release process issue template
A Github issue template to help formalizing the release process, in
order to avoid human errors in the process.

Closes: https://github.com/damus-io/damus/issues/2752
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-02-07 10:45:54 -08:00
Daniel D’Aquino
d4d17fcbad Add release process issue template
A Github issue template to help formalizing the release process, in
order to avoid human errors in the process.

Closes: https://github.com/damus-io/damus/issues/2752
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-02-05 19:35:59 +00:00
Daniel D’Aquino
c21d29a897 Improve clarity of mute button to indicate it serves as a block feature
Changelog-Changed: Improved clarity of the mute button to indicate it can be used for blocking a user
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-02-03 18:33:01 -08:00
Daniel D’Aquino
6e117ac39c Improve Microphone usage description
This makes the microphone access request contain a message that is more
clear to the user

Changelog-Changed: Made the microphone access request message more clear to users
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-02-03 18:33:01 -08:00
Daniel D’Aquino
79407f17e8 Add double star for Purple members that have been active for over a year
This commit adds a special badge for purple members who have been active
for more than one entire year.

Closes: https://github.com/damus-io/damus/issues/2831
Changelog-Added: Purple members who have been active for more than a year now get a special badge
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-01-29 21:36:36 -08:00
Daniel D’Aquino
72c19fc411 Unsubscribe from push notifications on logout
Closes: https://github.com/damus-io/damus/issues/1707
Changelog-Fixed: Fixed issue where users continue to receive push notifications after logout
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-01-24 10:42:29 -08:00
Daniel D’Aquino
24c3e61a4b Make drafts persistent
This commit makes drafts persistent.

It does so by:
1. Converting `DraftsArtifacts` into Nostr events
2. Wrapping those Nostr events into NIP-37 notes
3. Saving those NIP-37 notes into NostrDB
4. Loading those same notes at startup
5. Unwrapping NIP-37 notes into Nostr events
6. Parsing that into `DraftsArtifacts`, loaded into DamusState
7. PostView can then load these drafts

Furthermore, a UX indicator was added to show when a draft has been
saved.

Limitations:
1. No encoding/decoding roundtrip guarantees. That would require
   extensive and heavy refactoring which is out of the scope of this
   commit.
2. We rely on `UserSettings` to keep track of note ids, while we do not
   have Ndb query capabilities
3. No NIP-37 relay sync support has been added yet, as that adds
   important privacy and sync conflict considerations which are out of
   the scope of this ticket, which is ensuring people don't lose their
   progress while writing notes.
4. The main use cases and scenarios have been tested. Because of (1),
   there may be some small inconsistencies on the stored version of the
   draft, but care was taken to keep the substantial portions of the
   content intact.

Closes: https://github.com/damus-io/damus/issues/1862
Changelog-Added: Added local persistence of note drafts
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-01-24 10:36:46 -08:00
Daniel D’Aquino
74d5bee1f6 Fix disappearing events on thread view
This commit fixes an issue where events in threads would occasionally
disappear.

Previously, the computation of parent events and reply events depended
on EventCache and had to be manually computed upon event selection
change. This may lead to inconsistencies if the computation is not
re-done after a new event that leads to a change in the model, or if certain
events are not yet on the cache. Instead, these are now computed
properties inside ThreadModel, and relies exclusively on the events
already in the ThreadModel.

Several other smaller improvements were made around the affected class,
including:
- Removing unused code for simplicity
- Configuring the class external interface with more intent, avoiding
  misusage
- Adding more documentation on the usage of things, as well as
  implementation notes on why certain design decisions were taken.
- Moving things to explicit actors, to integrate more structured concurrency
- Improving code efficiency to lower computational overhead on the main
  actor
- Splitting concerns between objects with more intent and thoughful
  design.

Changelog-Fixed: Fixed an issue where events on a thread view would occasionally disappear
Closes: https://github.com/damus-io/damus/issues/2791
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-01-24 10:36:46 -08:00
Daniel D’Aquino
8066fa1bf8 Improve robustness of the URL handler
This commit improves reliability on the handling of
external URLs.

This was achieved through the following improvements:
1. The URL handler interface is now well-defined, with more clear inputs
   and outputs, to avoid silent failures and error paths that are hard to see
   within convoluted logic paths
2. Side effects during URL parsing were almost completely removed for
   more predictable behavior
3. Error handling logic was added to present errors to the user in a user-friendly manner,
   instead of silently failing
4. Event loading logic was moved into a special new thread view, which
   makes its own internal state evident to the user (i.e. whether
   the note is loading, loaded, or if the note could not be found)

These changes make the URL opening logic more predictable, easy to
refactor, and helps ensure the user always gets some outcome from
opening a URL, even if it means showing a "not found" or "error" screen,
to eliminate cases where nothing seems to happen.

Closes: https://github.com/damus-io/damus/issues/2429
Changelog-Fixed: Improved robustness of the URL handler
Changelog-Added: Added user-friendly error view for errors around the app that would not fit in other places
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-01-24 10:05:55 -08:00
26df547605 Remove language filtering from Universe feed because language detection can be inaccurate
Changelog-Removed: Removed language filtering from Universe feed because language detection can be inaccurate

Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-01-22 17:23:00 +09:00
a97532b90d Translate notes even if they are in a preferred language but not the current language as that is what users expect
Changelog-Fixed: Translate notes even if they are in a preferred language but not the current language as that is what users expect

Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-01-22 17:23:00 +09:00
Daniel D’Aquino
e8ba1ec806 Merge pull request #2812 from damus-io/translations
Translations
2025-01-22 16:56:56 +09:00
Daniel D’Aquino
e8c265a4d8 Version bump to 1.13
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-01-22 14:03:22 +09:00
Daniel D’Aquino
b33dc63fe4 v1.12 changelog
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-01-22 13:56:42 +09:00
transifex-integration[bot]
c4852f1309 Translate Localizable.strings in hu_HU
100% translated source file: 'Localizable.strings'
on 'hu_HU'.
2025-01-21 13:36:41 +00:00
transifex-integration[bot]
39a4be7076 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2025-01-20 20:01:03 +00:00
transifex-integration[bot]
50c7edc420 Translate Localizable.strings in nl
100% translated source file: 'Localizable.strings'
on 'nl'.
2025-01-20 19:40:49 +00:00
transifex-integration[bot]
67fa3c1ce5 Translate Localizable.strings in nl
100% translated source file: 'Localizable.strings'
on 'nl'.
2025-01-20 19:40:37 +00:00
transifex-integration[bot]
cd671da3e7 Translate Localizable.strings in nl
100% translated source file: 'Localizable.strings'
on 'nl'.
2025-01-20 19:40:30 +00:00
transifex-integration[bot]
3b60ca04f1 Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2025-01-20 11:46:31 +00:00
transifex-integration[bot]
e2e58499f5 Translate Localizable.strings in ja
100% translated source file: 'Localizable.strings'
on 'ja'.
2025-01-20 00:40:20 +00:00
5cadf09665 Export strings for translation 2025-01-19 12:29:10 -05:00
transifex-integration[bot]
1ca7b3462f Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:10 -05:00
transifex-integration[bot]
8a552d2b0f Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:10 -05:00
transifex-integration[bot]
9fa0f18f78 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:10 -05:00
transifex-integration[bot]
db672ca048 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:09 -05:00
transifex-integration[bot]
18ad73cd35 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:09 -05:00
transifex-integration[bot]
5719e9b37e Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:09 -05:00
transifex-integration[bot]
9fb2b3c0e5 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:09 -05:00
transifex-integration[bot]
5ec66feb06 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:09 -05:00
transifex-integration[bot]
ccc301cfcc Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:09 -05:00
transifex-integration[bot]
c1b9d0b55e Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:09 -05:00
transifex-integration[bot]
d9daa27016 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:08 -05:00
transifex-integration[bot]
fa3b5d57ed Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:08 -05:00
transifex-integration[bot]
7c3e598ca6 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:08 -05:00
transifex-integration[bot]
563d5c7881 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:08 -05:00
transifex-integration[bot]
b8cba0ee17 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:08 -05:00
transifex-integration[bot]
8556586af4 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:08 -05:00
transifex-integration[bot]
5fc52bb31b Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:08 -05:00
transifex-integration[bot]
a92c9f2c38 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:08 -05:00
transifex-integration[bot]
61e137696e Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:07 -05:00
transifex-integration[bot]
8fc3b124da Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:07 -05:00
transifex-integration[bot]
7852822295 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:07 -05:00
transifex-integration[bot]
85e55953b3 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:07 -05:00
transifex-integration[bot]
077f633f33 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:07 -05:00
transifex-integration[bot]
1c3d1598a3 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:07 -05:00
transifex-integration[bot]
314608627e Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:07 -05:00
transifex-integration[bot]
aeecc04b29 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:06 -05:00
transifex-integration[bot]
341389d438 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2025-01-19 12:21:06 -05:00
transifex-integration[bot]
fbeae64123 Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2025-01-19 12:21:05 -05:00
ericholguin
7a4af31859 nwc: Coinos
This PR adds a button to allow users to easily connect to Coinos
Also cleans up and organizes assets.

Changelog-Added: Coinos connection button in Wallet view

Signed-off-by: ericholguin <ericholguin@apache.org>
2025-01-12 15:20:06 +09:00
Tomek ⚡ K
e106be1412 Add Alby Go to mobile wallets selection
Changelog-Added: Added Alby Go to mobile wallets selection menu
Signed-off-by: Tomek K <itstomekk@getalby.com>
2025-01-12 11:33:20 +09:00
Swift Coder
282bf80daa Cancel ongoing uploading operations after cancelling post
1] Cancel ongoing uploading operations after the user has pressed "cancel post"
2] Don't generate haptic feedback in this error case because user has already dismissed the Post View

Changelog-Fixed: Cancel ongoing uploading operations after the user cancels the post
Signed-off-by: Swift Coder <scoder1747@gmail.com>
2025-01-06 15:55:53 +09:00
Daniel D’Aquino
bcb861a61b Improve accessibility of EditPictureControl
This commit improves accessibility of EditPictureControl, by adding
better accessibility labels and hints.

Changelog-Added: Minor accessibility improvements around picture editing and onboarding
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-01-06 15:45:58 +09:00
Daniel D’Aquino
bb0ad18913 Implement profile image cropping and optimization
This commit implements profile image cropping and optimization, as well
as a major refactor on EditPictureControl.

It now employs the following techniques:
- Users can now crop their profile pictures to fit a square aspect
  ratio nicely and avoid issues with automatic resizing/cropping
- Profile images are resized to a 400px by 400px image before sending it
  over the wire for better bandwidth usage
- Profile pictures are now tagged as such to the media uploaders, to
  enable media optimization or special care on their end.

Integrating the cropping step was very difficult with the previous
structures, so `EditPictureControl` was heavily refactored to have
improved state handling and better testability:

1. Enums with associated values are being used to capture all of the
   state in the picture selection process, as that helps ensure the
   needed info in each step is there and more clearly delianeate
   different steps — all at compile-time
2. The view was split into a view-model architecture, with almost all of
   the view logic ported to the new view-model class, making the view
   and the logic more clear to read as concerns are separated. This also
   enables better testabilty

Several automated tests were added to cover EditPictureControl logic and
looks.

Closes: https://github.com/damus-io/damus/issues/2643
Changelog-Added: Profile image cropping tools
Changelog-Changed: Improved profile image bandwidth optimization
Changelog-Changed: Improved reliability of picture selector
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-01-06 15:45:57 +09:00
Daniel D’Aquino
81830c7540 Add SwiftyCrop dependency
This commit adds the SwiftyCrop dependency, to provide users with a way
to crop their profile images prior to upload

- Dependency version is commit-hash-locked for extra security and
  reproducibility
- Reviewed code contents of the library to check for any user tracking
  code. None was found

Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-01-06 15:45:57 +09:00
transifex-integration[bot]
68128b5ff1 Translate Localizable.strings in hu_HU
100% translated source file: 'Localizable.strings'
on 'hu_HU'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
aebeb26bc6 Translate Localizable.strings in ja
100% translated source file: 'Localizable.strings'
on 'ja'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
79cf3db279 Translate Localizable.strings in ja
100% translated source file: 'Localizable.strings'
on 'ja'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
dcae0d2cc7 Translate Localizable.strings in ja
100% translated source file: 'Localizable.strings'
on 'ja'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
2b12dc5920 Translate Localizable.strings in nl
100% translated source file: 'Localizable.strings'
on 'nl'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
51930e7a12 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
b04e09d2e0 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-12-27 20:36:57 +09:00
b6c4213515 Export strings for translation 2024-12-27 20:36:57 +09:00
transifex-integration[bot]
8230c6eded Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
e79590f795 Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
79bced1246 Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
896f4b55e3 Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
52e65f9429 Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
a22cc532e2 Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
823227920c Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
3e2bbce25e Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
e05b2d9ecf Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
d7b31a1cd8 Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
70f01c0880 Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
2cf5f21f78 Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
96e8f8b6b2 Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
370cfd1b08 Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
046af15734 Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
9e4ab2d54c Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
7cf12e2e0d Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
a63a81b387 Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
d994cd13dc Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
95e985cfce Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
3a69de9274 Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
64f5acf98c Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
5167ab264d Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
e02895b29f Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
0009d11025 Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
afc317bb52 Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
629212ea23 Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
transifex-integration[bot]
ec1252200f Translate InfoPlist.strings in pt_PT
100% translated source file: 'InfoPlist.strings'
on 'pt_PT'.
2024-12-27 20:36:57 +09:00
Swift Coder
54ea1ab803 MacOS Damus Support allowing link and photo sharing option
Changelog-Fixed: Fixed link and photo sharing support on macOS
Signed-off-by: Swift Coder <scoder1747@gmail.com>
2024-12-27 19:13:45 +09:00
Swift Coder
4cf8097de4 Displaying suitable text instead of Empty Notification View
Changelog-Fixed:Handle empty notification pages by displaying suitable text
Signed-off-by: Swift Coder <scoder1747@gmail.com>
2024-12-20 11:01:02 +09:00
Daniel D’Aquino
2c7384b0a9 Fix button hidden behind software keyboard in create account view
This commit fixes an issue where the "next" button is hidden behind the
software keyboard in the account creation view, where it is very hard to
press.

The fix was done by dynamically shrinking the profile picture size when
keyboard appears in smartphone screens, so that there is enough space
for all content to appear.

Changelog-Fixed: Fixed issue where the "next" button would appear hidden and hard to click on the create account view
Closes: https://github.com/damus-io/damus/issues/2771
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-12-20 10:38:20 +09:00
Swift Coder
19e312a8fb Fix non scrollable wallet screen
Changelog-Fixed: Fix non scrollable wallet screen
Signed-off-by: Swift Coder <scoder1747@gmail.com>
2024-12-18 11:27:51 +09:00
Swift Coder
3986308638 Render Gif and video files while composing posts
Changelog-Added: Render Gif and video files while composing posts
Signed-off-by: Swift Coder <scoder1747@gmail.com>
2024-12-16 17:22:12 +09:00
fa7740948b Export strings for translation
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2024-12-16 17:04:20 +09:00
892a1420f3 Fix suggested users category titles to be localizable
Changelog-Fixed: Fixed suggested users category titles to be localizable

Signed-off-by: Terry Yiu <git@tyiu.xyz>
2024-12-16 17:04:20 +09:00
ee4cbf7363 Fix GradientFollowButton to have consistent width and autoscale text limited to 1 line
Changelog-Fixed: Fixed GradientFollowButton to have consistent width and autoscale text limited to 1 line

Signed-off-by: Terry Yiu <git@tyiu.xyz>
2024-12-16 17:04:20 +09:00
a1b1ce949b Fix right-to-left localization issues
Changelog-Fixed: Fixed right-to-left localization issues

Signed-off-by: Terry Yiu <git@tyiu.xyz>
2024-12-16 17:04:20 +09:00
902e8c3950 Fix AddMuteItemView to trim leading and trailing whitespaces from mute text and disallow adding text with only whitespaces
Changelog-Fixed: Fixed AddMuteItemView to trim leading and trailing whitespaces from mute text and disallow adding text with only whitespaces

Signed-off-by: Terry Yiu <git@tyiu.xyz>
2024-12-16 17:04:20 +09:00
b776788b38 Fix SideMenuView text to autoscale and limit to 1 line
Changelog-Fixed: Fixed SideMenuView text to autoscale and limit to 1 line

Signed-off-by: Terry Yiu <git@tyiu.xyz>
2024-12-16 17:04:20 +09:00
Daniel D’Aquino
78066773f4 Improve clarity of word search label
Changelog-Changed: Improved UX around the label for searching words
Closes: https://github.com/damus-io/damus/issues/2733
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-12-13 14:00:00 +09:00
Daniel D’Aquino
0bac284eee Fix issues with inputting a profile twice to the search bar
This fixes an issue where a user would have to input a profile npub
twice in order to get a result.

The fix is composed of the following constituents:
1. The removal of the dependency on NostrDB having profile information.
   Previously the function relied on NostrDB having profile information
   about a freshly downloaded profile, which it sometimes does not. The
   function does not require the profile to be on NostrDB at the time
   the profile is found on the relay.
2. The increase in allowed relay attempts to all relays. Previously it
   would only look for about half of the relays, which could cause
   certain events to not be found
3. The closing of relay subscription on EOSE. Previously, the
   subscription would only be closed if an event was found, which could
   lead to a "leak" of open subscriptions if an event is not found.

Closes: https://github.com/damus-io/damus/issues/2635
Changelog-Fixed: Fixed an issue where a profile would need to be input twice in the search to be found
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-12-13 14:00:00 +09:00
Daniel D’Aquino
07c95d1003 Turn on strict concurrency checks
Turn on strict concurrency checks on the compiler to make potential
concurrency issues more visible and aid during debugging, as well as to
start preparing us for Swift 6.

Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-12-13 14:00:00 +09:00
Daniel D’Aquino
1072c5a384 Version bump to 1.12
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-12-09 18:05:12 +09:00
transifex-integration[bot]
5ed6e85ad8 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
f948dd81ca Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
391818f230 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
dc74ad37a1 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
e1c94b7ff9 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
ec933452d3 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
977b268023 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
0c778af833 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
e75e7950b5 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
8d68297cce Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
e0fd24aff5 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
b5c3ff45e4 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
786dbb21c4 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
5a17c330da Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
975be63ce1 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
d9796bd63c Translate Localizable.stringsdict in ar
100% translated source file: 'Localizable.stringsdict'
on 'ar'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
25a835624a Translate Localizable.strings in ar
100% translated source file: 'Localizable.strings'
on 'ar'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
1d06683bb3 Translate Localizable.stringsdict in pt_PT
100% translated source file: 'Localizable.stringsdict'
on 'pt_PT'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
8e15a86c0a Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
51a3008e5a Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
f71c1b9848 Translate InfoPlist.strings in pt_PT
100% translated source file: 'InfoPlist.strings'
on 'pt_PT'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
151e23d524 Translate InfoPlist.strings in pt_PT
100% translated source file: 'InfoPlist.strings'
on 'pt_PT'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
7619891c86 Translate InfoPlist.strings in pt_PT
100% translated source file: 'InfoPlist.strings'
on 'pt_PT'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
cc98525f59 Translate InfoPlist.strings in pt_PT
100% translated source file: 'InfoPlist.strings'
on 'pt_PT'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
8cf9549981 Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
9ebf27cd37 Translate Localizable.strings in pt_PT
100% translated source file: 'Localizable.strings'
on 'pt_PT'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
16a1a9f37f Translate Localizable.strings in ja
100% translated source file: 'Localizable.strings'
on 'ja'.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
08d28b0f00 Translate Localizable.strings in nl
100% translated source file: 'Localizable.strings'
on 'nl'.
2024-12-09 18:00:42 +09:00
d0ae3ca08a Fix non-breaking spaces in localized strings
Changelog-Fixed: Fixed non-breaking spaces in localized strings

Signed-off-by: Terry Yiu <963907+tyiu@users.noreply.github.com>
2024-12-09 18:00:42 +09:00
6e2f770876 Revert "Replace non-breaking spaces with regular spaces as Apple's NSLocalizedString macro does not seem to work with it"
This reverts commit 4adcb738a2.
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
4079bea912 Translate Localizable.strings in ja
100% translated source file: 'Localizable.strings'
on 'ja'.
2024-12-09 18:00:42 +09:00
4d01340b90 Fix localization issue on Add mute item button
Changelog-Fixed: Fixed localization issue on Add mute item button

Signed-off-by: Terry Yiu <963907+tyiu@users.noreply.github.com>
2024-12-09 18:00:42 +09:00
transifex-integration[bot]
61b89c2f54 Translate Localizable.strings in nl
100% translated source file: 'Localizable.strings'
on 'nl'.
2024-12-09 18:00:42 +09:00
Swift Coder
cbdff4a5f8 Add profile info text in stretchable banner with follow button
Changelog-Added: Add profile info text in stretchable banner with follow button
Signed-off-by: Swift Coder <scoder1747@gmail.com>
2024-12-09 17:58:16 +09:00
Swift Coder
866afe970b Paste Gif image similar to jpeg and png files
This commit change will allow users to paste GIF file in the Post by copying from other apps (previously similar to pasting Jpeg and PNG image functionality)

Changelog-Added: Paste Gif image similar to jpeg and png files
Signed-off-by: Swift Coder <scoder1747@gmail.com>
2024-12-09 16:46:40 +09:00
transifex-integration[bot]
87efc91527 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-12-03 18:18:41 +09:00
4121526588 Export strings for translation
Signed-off-by: Terry Yiu <963907+tyiu@users.noreply.github.com>
2024-12-03 18:18:41 +09:00
4adcb738a2 Replace non-breaking spaces with regular spaces as Apple's NSLocalizedString macro does not seem to work with it
Changelog-Fixed: Replace non-breaking spaces with regular spaces as Apple's NSLocalizedString macro does not seem to work with it

Signed-off-by: Terry Yiu <963907+tyiu@users.noreply.github.com>
2024-12-03 18:18:41 +09:00
1f17f19a6e Fix localization issues in RelayConfigView
Changelog-Fixed: Fixed localization issues in RelayConfigView

Signed-off-by: Terry Yiu <963907+tyiu@users.noreply.github.com>
2024-12-03 18:18:41 +09:00
transifex-integration[bot]
fb54115286 Translate InfoPlist.strings in pt_PT
100% translated source file: 'InfoPlist.strings'
on 'pt_PT'.
2024-12-03 18:18:41 +09:00
transifex-integration[bot]
50dd35d089 Translate Localizable.strings in vi
100% translated source file: 'Localizable.strings'
on 'vi'.
2024-12-03 18:18:41 +09:00
transifex-integration[bot]
1205b2a0e2 Translate Localizable.strings in ar
100% translated source file: 'Localizable.strings'
on 'ar'.
2024-12-03 18:18:41 +09:00
transifex-integration[bot]
0a93e909ed Translate InfoPlist.strings in ar
100% translated source file: 'InfoPlist.strings'
on 'ar'.
2024-12-03 18:18:41 +09:00
transifex-integration[bot]
6f3f928ac3 Translate InfoPlist.strings in bg
100% translated source file: 'InfoPlist.strings'
on 'bg'.
2024-12-03 18:18:41 +09:00
transifex-integration[bot]
637ceabede Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2024-12-03 18:18:41 +09:00
transifex-integration[bot]
c25f54f7e7 Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2024-12-03 18:18:41 +09:00
transifex-integration[bot]
d4ae0b1346 Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2024-12-03 18:18:41 +09:00
transifex-integration[bot]
7773618547 Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2024-12-03 18:18:41 +09:00
transifex-integration[bot]
a4199fa299 Translate Localizable.strings in pl_PL
100% translated source file: 'Localizable.strings'
on 'pl_PL'.
2024-12-03 18:18:41 +09:00
transifex-integration[bot]
5b9ccc4ee5 Translate Localizable.stringsdict in pl_PL
100% translated source file: 'Localizable.stringsdict'
on 'pl_PL'.
2024-12-03 18:18:41 +09:00
transifex-integration[bot]
f538e03093 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-12-03 18:18:41 +09:00
transifex-integration[bot]
e625297a2e Translate Localizable.strings in ja
100% translated source file: 'Localizable.strings'
on 'ja'.
2024-12-03 18:18:41 +09:00
transifex-integration[bot]
e603678872 Translate Localizable.strings in nl
100% translated source file: 'Localizable.strings'
on 'nl'.
2024-12-03 18:18:41 +09:00
transifex-integration[bot]
9d77f1b2f7 Translate Localizable.strings in hu_HU
100% translated source file: 'Localizable.strings'
on 'hu_HU'.
2024-12-03 18:18:41 +09:00
c4f7d25793 Fix localization issues and export strings for translation 2024-12-03 18:18:41 +09:00
transifex-integration[bot]
100f195a03 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-12-03 18:18:41 +09:00
Swift Coder
e599ef1ac9 Fix duplicate uploads
Reset orderIds and orderMap

Changelog-Fixed: Fix duplicate uploads
Signed-off-by: Swift Coder <scoder1747@gmail.com>
2024-12-03 17:31:55 +09:00
Swift Coder
033c69b92e Remove duplicate pubkey from Follow Suggestion list
Changelog-Fixed: Remove duplicate pubkey from Follow Suggestion list
Signed-off-by: Swift Coder <scoder1747@gmail.com>
2024-12-02 15:43:02 +09:00
Swift Coder
184e566b1b Fix Page control indicator for not reflecting current index of Image being previewed
Changelog-Fixed: Fix Page control indicator
Signed-off-by: Swift Coder <scoder1747@gmail.com>
2024-12-02 15:27:14 +09:00
Swift Coder
8c321e479b Fix Damus sharing issues
1. While sharing images/videos from Apple's Message app, the file will be treated as a Link with file-url. The if-else ordering will help to fix the issue.
2. While sharing image from Signal and Facebook app, the file being received is an UIImage and error is being sent. This PR fixes the issue.

Changelog-Fixed: Fix damus sharing issues
Signed-off-by: Swift Coder  <scoder1747@gmail.com>
2024-12-02 15:22:13 +09:00
Daniel D’Aquino
960c84d02e Fix CHANGELOG markdown syntax issue
Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-11-22 11:49:19 -08:00
Daniel D’Aquino
02f1c2d342 Add script to help identify duplicate changelog entries
This commit adds a new script to devtools that can be used to help
identify duplicate changelog entries.

It works by identifying duplicate lines in CHANGELOG.md, and then
searching whether each one of those duplicate lines are present in a
separate text file (which can be a subset of the changelog that the user
is interested in analyzing)

No user-facing changes

Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-11-22 11:42:35 -08:00
Daniel D’Aquino
c8ca3c93f6 Changelog entry for 1.11(10)
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-11-22 11:42:35 -08:00
Daniel D’Aquino
5c6e5ca2de Add edit banner button UI automated test + accessibility improvements
This commit adds an automated UI test to check if the edit banner button
UI is clickable and not hidden behind a top bar or another invisible
element.

It also improves accessibility support for some elements on login and
top bar.

Changelog-Changed: Improved accessibility support on some elements
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-11-20 14:44:06 -08:00
Daniel D’Aquino
e3105a90c5 Move edit banner button into safe area
In some conditions, it was found that the banner edit button was
obscured behind a top nav bar.

This commit fixes that by introspecting on the safe area margins and
applying them to the button

Closes: https://github.com/damus-io/damus/issues/2636
Changelog-Fixed: Fixed issue where banner edit button is unclickable
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-11-20 14:44:06 -08:00
Daniel D’Aquino
38dc7b046a Fix issues with new Share extension
This commit fixes the following issues with the new Share extension:
- Typo on user-facing label
- Misconfigured Info.plist that caused the build to be rejected by AppStore Connect

This extension was never shipped to users, so no changelog entry is needed.

Changelog-None
Fixes: eeb6547d3e
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-11-18 11:43:24 -08:00
Daniel D’Aquino
da76ad9b66 Fix logical merge error
This commit fixes build errors caused by logical merge issues from
changes that worked in isolation but not when combined.

Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-11-18 10:32:09 -08:00
Swift Coder
177c55cf3d Fix missing tab bar while navigating
Set isSidebarVisible to false

Changelog-Fixed: missing tab bar on navigation
Signed-off-by: Swift Coder <scoder1747@gmail.com>
2024-11-15 17:17:10 -08:00
Swift
eeb6547d3e Add Damus Share Feature
This PR change adds Damus Share feature to the app that allows the users to share Photos and URLs from foreign apps.

Changelog-Added: Add Damus Share Feature

Signed-off-by: Swift Coder  <scoder1747@gmail.com>
2024-11-15 17:08:44 -08:00
Daniel D’Aquino
50ef6600a8 Make QR code scanning more robust
1. Removed the dependency on finding the profile event for displaying actions to the user, even if the full profile couldn't be loaded. This allowed showing useful options such as the option to follow that pubkey.
2. Opened a profile preview sheet instead of navigating to the full profile page, enabling quick actions and saving bandwidth by not loading their timeline immediately.
3. Refactored most of that view to simplify state management and make it less prone to errors.
4. Improved error handling and management.
5. Ensured the view truly reflected the internal state of the scanner to the user.

Changelog-Fixed: Fixed some issues where QR code would not work, and improved UX
Closes: https://github.com/damus-io/damus/issues/2032
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-11-15 15:41:04 -08:00
Daniel D’Aquino
be43819de2 Update and refactor ImageCarousel fill handling
Previously, the ImageCarousel needed to directly set a video size
binding to the video player view, in order to communicate and listen to
video size changes, and it used that to calculate the carousel image fill.

However, in the new video coordination architecture, the video size is
not owned by the ImageCarousel, but instead it is owned by the video
player itself, which in turn is owned by the video coordinator.
Therefore, this is incompatible with several logic elements of
ImageCarousel.

This commit updates the image carousel to integrate with the new video
coordinator architecture, and it also refactors the image fill logic
almost completely — with a focus on reducing stateful behavior by
carefully employing some state management patterns.

Furthermore, the new CarouselModel was heavily documented to explain its
design decisions and inner workings.

Note: There used to be some caching on the ImageFill calculations, but
after using this new refactored version without caching, I have not
noticed any noticeable performance regressions, so I have decided not to
add them back — applying Occam's razor

Changelog-Changed: Improved image carousel image fill behavior
Closes: https://github.com/damus-io/damus/issues/2458
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-11-11 15:30:17 -08:00
Daniel D’Aquino
58017952bc Video coordination improvements and new video controls view
This commit makes several improvements to video coordination,
and implements a new video control view.

The video support stack in Damus has been re-architected to achieve
this.

The new architecture can be summarized as follows:
1. `DamusVideoCoordinator` is a singleton object in `DamusState`, and it
   is responsible for deciding which video should have the "main stage"
   focus, based on main stage requests that video player views make when
   they become visible.

   Having "main stage" focus means that the coordinator will auto-play
   that video and pause others, and is used throughout the app to
   determine which video to talk to or control, in the case of app-wide
   controls (analogous to how Apple Music needs to know which song is
   playing for displaying playback controls on the iOS home screen)

   Having a singleton take care of this establishes
   clear ownership and prevents conflicts such as double-playing video.

   This coordinator also holds a pool of video media items (`DamusVideoPlayer`),
   with exactly ONE `DamusVideoPlayer` per URL, to reduce
   bandwidth and ensure perfect syncing of the same video in different
   contexts.

2. `DamusVideoPlayer` objects hold the actual media item (video data, playback state),
   much like `AVPlayer`.
   In fact, `DamusVideoPlayer` can be described as a wrapper for `AVPlayer`,
   except it has an interface that is much more SwiftUI friendly,
   enabling playback state syncing with minimal effort.

   `DamusVideoPlayer` is NOT a view. And there is only ONE `DamusVideoPlayer`
   per URL — held by the coordinator.
   However, when the app needs to display that same video in multiple
   places, the app can instantiate multiple video player VIEWS of the
   same `DamusVideoPlayer`

3. `DamusVideoPlayer.BaseView` is the most basic video player view for a
   `DamusVideoPlayer` item. It has basically no features other than
   showing the video itself.

4. `DamusVideoPlayerView` is the standard, batteries-included, video
   player view for `DamusVideoPlayer` items, that is used throughout the
   app.

   It also tries to detect its own visibility, and makes requests to
   `DamusVideoCoordinator` to take over the main stage when it becomes
   visible.

5. `DamusVideoControlsView` is a view that presents video playback
   controls (play/pause, mute, scrubbing) for a `DamusVideoPlayer`
   object.

How a `DamusVideoPlayerView` gains and loses main stage focus:
1. `DamusVideoPlayerView` uses `VisibilityTracker` to find out when it
   becomes visible or not
2. When it becomes visible, it makes a request to the video coordinator
   to take main stage focus. The request also specifies which layer the
   video view is in (Full screen layer? Normal app layer?), which the
   video player view gets from the `\.view_layer_context` environment
   variable set by `damus_full_screen_cover`
3. The coordinator (`DamusVideoCoordinator`) keeps all of these
   requests, and uses its own internal logic and info to determine which
   video should get the main stage.
   The logic also depends on whether or not the app finds itself in full
   screen mode.
   Once the main stage is given to a different video, the previous video
   is paused, the main-staged-video is played, and the requestor
   receives a callback.
4. Once the video disappears from view, it tells the coordinator that it
   is giving up the main stage, and the coordinator then picks another
   main stage request again.

On top of this, several of other small changes and improvements were made,
such as video gesture improvements

Note: This commit causes some breakage over the image carousel sizing
logic, which will be addressed separately in the next commit.

Changelog-Fixed: Fixed iOS 18 gesture issues that would take user to the thread view when clicking on a video or unmuting it
Changelog-Fixed: Fixed several issues that would cause video to automatically play or pause incorrectly
Changelog-Fixed: Fixed issue where full screen video would disappear when going to landscape mode
Changelog-Added: Added new easy to use video controls for full screen video
Changelog-Changed: Improved video syncing and bandwidth usage when switching between timeline video and full screen mode
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-11-11 15:30:17 -08:00
Daniel D’Aquino
409be7fc58 Refactor visibility tracker
This commit moves all logic related to visibility tracking into a single
view modifier for better code reusability.

Furthermore, the modified VisibilityTracker component was more
extensively documented, for better awareness of its limitations and
usage.

Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-11-11 15:30:17 -08:00
Daniel D’Aquino
1bc660c9cd Improve full screen support
This commit introduces new mechanisms to solve some issues with full screen support:
1. Full screen covers disappear when its caller disappears (e.g. when it
   is an event in a lazy stack, and an orientation change causes the
   view to disappear along with the full screen cover)
2. There are no mechanisms for views to determine whether they are being
   presented under a full screen cover or not, and whether the device is
   in full screen mode or not.

The commit overcomes the above limitations through the following:
1. A full screen cover on `ContentView` that can be accessed by any view
   when calling `present(fullScreenItem)`
2. A new `damus_full_screen_cover` view modifier that automatically
   tracks whether a device is in full screen mode or not, and allows
   any descendant view in its hierarchy to introspect on which view
   layer it is being presented in.

This commit lays a foundation that will later become important for
improving video coordination.

Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-11-11 15:30:17 -08:00
Daniel D’Aquino
a56a59f81d Improve SwipeToDismiss modifier UX
This commit adds an opacity transition when swiping to dismiss an item,
to make it clear that the user is about to dismiss it.

Changelog-Changed: Swipe to dismiss on full screen carousel now shows an opacity effect for improved UX
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-11-11 15:30:17 -08:00
Daniel D’Aquino
1d5af6ca5c Remove event details from full screen carousel
Changelog-Changed: Removed event contents from full screen media carousel for cleaner view
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-11-11 15:30:17 -08:00
Daniel D’Aquino
f81b2b677f Fix portrait video sizing on full screen carousel
Changelog-Fixed: Fixed portrait video size on full screen carousel
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-11-11 15:30:17 -08:00
Daniel D’Aquino
290152c859 Rename VideoController to DamusVideoCoordinator
This commit renames this class to better represent what it does.

This reduces some of the term overloading between this class and other video
controller classes/structs. (Such as AVPlayerController)

Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-11-11 15:30:17 -08:00
Swift
c4ee52fdac Add sharing option in image carousel view (#2629)
Add share button in Full screen image carousel view images

The ellipsis (share button) allows you to share the current image being displayed in the full screen carousel viewer.

Changelog-Changed: Add share button for images on full screen image carousel view
Signed-off-by: Swift Coder <scoder1747@gmail.com>
2024-11-11 14:36:27 -08:00
Swift Coder
6f04455350 Add Edit, Share, and Tap-gesture in Profile pic image viewer
Add Edit button that navigates onto Profile Page
Add ShareLink button that allows us to Share actual image
Add Tap gesture in profile pic image viewer

Changelog-Added: Add Edit, Share, and Tap-gesture in Profile pic image viewer
Signed-off-by: Swift Coder <scoder1747@gmail.com>
2024-11-04 13:22:57 -08:00
Daniel D’Aquino
3b62945e5b Revert "fix: regression that dropped q tags from quote reposts"
This reverts commit 5865b000c0.
2024-11-01 11:25:24 -07:00
Swift Coder
b1b032d905 postview: add hashtag suggestions
Closes: #2604
Changelog-Changes: Add hashtag suggestions to post view
Signed-off-by: Swift Coder <scoder1747@gmail.com>
2024-10-28 11:49:47 -07:00
Swift Coder
7c805f7f23 fix: avatar image on qrcode view
Closes: #2612
Changelog-Fixed: Fix avator image on qrcode view
Signed-off-by: Swift Coder <scoder1747@gmail.com>
2024-10-28 11:45:45 -07:00
Swift Coder
a2b0620175 fix: banner image upload
There was a nostr.build auth issue when uploading banner images. This
fixes that.

Closes: #2614
Changelog-Fixed: Fix banner image uploa
Signed-off-by: Swift Coder <scoder1747@gmail.com>
2024-10-28 11:45:45 -07:00
William Casarin
8c6bee3d90 Merge remote-tracking branch 'github/pr/2622' 2024-10-28 11:40:16 -07:00
ericholguin
bba651b37c ui: reduce bold font in side menu
This PR simply reduces the bold font in the side menu labels.

Changelog-Changed: Changed boldness of font in side menu labels.

Signed-off-by: ericholguin <ericholguin@apache.org>
2024-10-26 21:55:28 -06:00
ericholguin
f657af275a ui: replace search notes button with searched word
This PR replaces the search notes button with the searched word.
This also removes the magnifying glass image from the search buttons.

Closes: #2601

Changelog-Changed: Changed search notes button with searched keyword

Signed-off-by: ericholguin <ericholguin@apache.org>
2024-10-26 21:36:59 -06:00
William Casarin
03ded7d39f Merge Translations #2603
Terry Yiu (1):
      Fix localization issues and export strings

Transifex (5):
      Translate Localizable.strings in th
      Translate Localizable.strings in ja
      Translate Localizable.strings in ja
      Translate Localizable.strings in nl
      Translate Localizable.strings in hu_HU
2024-10-26 11:35:49 -07:00
William Casarin
53edc7eb0b Merge 'fix: Fix overlap in Universe view' #2607
ericholguin (1):
      fix: Fix overlap in Universe view
2024-10-26 11:34:43 -07:00
William Casarin
8b969021d5 Merge 'ux: increase opacity of tabbar and post button' #2608
ericholguin (1):
      ux: increase opacity of tabbar and post button
2024-10-26 11:33:46 -07:00
William Casarin
1e52982a5d Merge 'fix: regression that dropped q tags from quote reposts' #2617
William Casarin (2):
      fix: regression that dropped q tags from quote reposts
2024-10-26 11:30:50 -07:00
William Casarin
0038d42f71 Merge 'dismiss button in full screen carousel' #2611
Swift Coder (2):
      Fix: dismiss button in full screen carousel
      Address PR Feedback
2024-10-26 11:25:27 -07:00
Swift Coder
d94b387fb9 Address PR Feedback
Use Switch statement to address all cases instead of if-else

Signed-off-by: Swift Coder <scoder1747@gmail.com>
2024-10-25 16:17:17 -04:00
Swift Coder
8a2dbc95ca Fix: dismiss button in full screen carousel
This updates the dismiss button on the fullscreen carousel
so that it is more visible in some scenarios.

Changelog-Fixed: Fix dismiss button visibility
Signed-off-by: Swift Coder <scoder1747@gmail.com>
2024-10-25 00:37:44 -04:00
William Casarin
5865b000c0 fix: regression that dropped q tags from quote reposts
It looks like some refactor broke q tags on quote reposts. This drops
the gather_quote_tags entirely and just relies on the logic in
build_post.

The references field wasn't being used for anything other than pubkeys,
so we switch to pubkeys directly.

Changelog-Fixed: Fix quote repost counting
Signed-off-by: William Casarin <jb55@jb55.com>
2024-10-24 15:31:02 -07:00
transifex-integration[bot]
6efb512a64 Translate Localizable.strings in hu_HU
100% translated source file: 'Localizable.strings'
on 'hu_HU'.
2024-10-22 11:14:57 +00:00
ericholguin
b7b8c7f175 ux: increase opacity of tabbar and post button
This PR simply increases the opacity of the tabbar and post button.
The increase in opacity makes the post button active.

Closes: #2598
Closes: #2599

Changelog-Changed: Changed opacity of tabbar and post button

Signed-off-by: ericholguin <ericholguin@apache.org>
2024-10-21 19:25:40 -06:00
ericholguin
a76e2aa677 fix: Fix overlap in Universe view
This PR fixes the overlapping text in the Universe View.

Changelog-Fixed: Fixed overlapping text in Universe View

Signed-off-by: ericholguin <ericholguin@apache.org>
2024-10-21 18:18:05 -06:00
William Casarin
d9f2317728 Merge 'Maintain images preview as per the selection order' from 'github/pr/2595'
Swift Coder (2):
      Maintain images preview as per the selection order
      document
2024-10-21 09:44:19 -07:00
transifex-integration[bot]
f1339e835b Translate Localizable.strings in nl
100% translated source file: 'Localizable.strings'
on 'nl'.
2024-10-21 08:32:58 +00:00
transifex-integration[bot]
64f2362be3 Translate Localizable.strings in ja
100% translated source file: 'Localizable.strings'
on 'ja'.
2024-10-21 01:49:49 +00:00
5b184a40fd Fix localization issues and export strings
Changelog-Fixed: Fixed localization issues and exported strings

Signed-off-by: Terry Yiu <963907+tyiu@users.noreply.github.com>
2024-10-20 23:00:33 +02:00
transifex-integration[bot]
17e6191a92 Translate Localizable.strings in ja
100% translated source file: 'Localizable.strings'
on 'ja'.
2024-10-17 17:32:04 +02:00
transifex-integration[bot]
1ff065d4c7 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2024-10-17 17:32:03 +02:00
Swift Coder
94e2c76284 document 2024-10-17 11:27:03 -04:00
Swift Coder
1925af6897 Maintain images preview as per the selection order 2024-10-17 11:23:02 -04:00
William Casarin
4effaa4324 Merge 'Side menu redesign' from 'github/pr/2569' into master
ericholguin (1):
      ui: Side menu redesign
2024-10-16 09:14:42 -07:00
William Casarin
e2a4443a9c Merge 'Fix padding for views for tabbar' from github/pr/2589 2024-10-16 09:09:24 -07:00
William Casarin
7c0e1c5ded Merge multiple image uploads
Changelog-Changed: Allow multiple images to be uploaded at the same time (swiftcoder)
2024-10-16 08:55:31 -07:00
William Casarin
f6e34ad999 Merge 'Fix sensitive chat bubble on iOS 18' 2024-10-16 08:47:39 -07:00
Swift Coder
ca5da7b5cd Ensures the order in which they were picked (with numbered badge selection) 2024-10-15 22:47:21 -04:00
Swift Coder
c08e4a2fdd Documenting 2024-10-15 10:48:48 -04:00
Swift Coder
37a50f6087 addressed upload issue in pr feedback 2024-10-15 10:43:32 -04:00
ericholguin
2040e79165 ui: Side menu redesign
This PR redesigns the side menu to more closely match Roberto's design

Changelog-Changed: Changed side menu design

Signed-off-by: ericholguin <ericholguin@apache.org>
2024-10-14 19:21:57 -06:00
Daniel D’Aquino
a6449020b6 Fix sensitive chat bubble on iOS 18
This commit fixes an issue with the chat bubble view where it would
unexpectedly trigger the reaction emoji keyboard when scrolling or
swiping, which became specially sensitive on iOS 18.

The fix consists of 2 parts:
- Changing the long press gesture logic to better adhere to Apple's API specs
- Modify the SwipeActions library to allow the gesture priority to be
  configurable, and demote the swiping gesture to have normal priority
  (it was found that having a high-priority drag gesture prevents
  long-presses from being activated)

Closes: https://github.com/damus-io/damus/issues/2577
Changelog-Fixed: Fix sensitive long-press gesture on event chat bubble in iOS 18
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-10-14 18:20:44 -07:00
ericholguin
75a46f4ab4 fixes: Fix padding for views for tabbar
This PR fixes the bottom padding on views to account for the bottom tabbar,
now that the tabbar is an overlay we must account for it.

Changelog-Fixed: Fixed bottom padding for tabbar

Signed-off-by: ericholguin <ericholguin@apache.org>
2024-10-14 19:07:01 -06:00
William Casarin
c948c7e230 search: truncate content
sometimes its too big for search results

Changelog-Changed: Truncate fulltext search results
Signed-off-by: William Casarin <jb55@jb55.com>
2024-10-14 12:08:25 -07:00
William Casarin
c83b0fba21 Merge 'paste images' support
Swift Coder (3):
      Allow-pasting-image-option
      Documenting
      Code optimization
2024-10-13 15:40:52 -07:00
William Casarin
b7053e8680 Merge 'ux: Seamless Timeline'
ericholguin (1):
      ux: Seamless Timeline
2024-10-13 15:14:40 -07:00
Swift Coder
17183632c8 Multiple images upload 2024-10-11 12:50:26 -04:00
Swift Coder
686d6d6e92 Code optimization 2024-10-08 17:05:04 -04:00
Swift Coder
847ae7b396 Documenting 2024-10-08 14:45:34 -04:00
Swift Coder
ba9780fb17 Allow-pasting-image-option 2024-10-08 13:52:30 -04:00
transifex-integration[bot]
42f5af0ffd Translate Localizable.strings in es_ES
100% translated source file: 'Localizable.strings'
on 'es_ES'.
2024-10-04 12:20:28 -07:00
transifex-integration[bot]
55f1330fc1 Translate Localizable.strings in nl
100% translated source file: 'Localizable.strings'
on 'nl'.
2024-10-04 12:20:28 -07:00
transifex-integration[bot]
4b326340a3 Translate Localizable.strings in nl
100% translated source file: 'Localizable.strings'
on 'nl'.
2024-10-04 12:20:28 -07:00
transifex-integration[bot]
83f7766833 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-10-04 12:20:28 -07:00
transifex-integration[bot]
1e3b20f5b3 Translate Localizable.strings in hu_HU
100% translated source file: 'Localizable.strings'
on 'hu_HU'.
2024-10-04 12:20:28 -07:00
transifex-integration[bot]
e508f28f7d Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2024-10-04 12:20:28 -07:00
transifex-integration[bot]
2c139863b8 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2024-10-04 12:20:28 -07:00
transifex-integration[bot]
c699409129 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2024-10-04 12:20:28 -07:00
transifex-integration[bot]
74e6d8781a Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2024-10-04 12:20:28 -07:00
transifex-integration[bot]
876f9c742f Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2024-10-04 12:20:28 -07:00
transifex-integration[bot]
1e7b57eaf3 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2024-10-04 12:20:28 -07:00
5615b1e1ec Fix localization build failures
Changelog-Fixed: Fixed localization build failures
Signed-off-by: Terry Yiu <963907+tyiu@users.noreply.github.com>
2024-10-04 12:20:28 -07:00
transifex-integration[bot]
9d66a5ed4f Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-10-04 12:20:28 -07:00
transifex-integration[bot]
5555f1afec Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-10-04 12:20:28 -07:00
ericholguin
77b1b895a5 ux: fix navigation placement in profile edit view
This PR fixes the issue with the placement of the back navigation button in the profile edit view for iOS 18 devices:

Changelog-Fixed: Fixed back nav button placement in profile edit view

Signed-off-by: ericholguin <ericholguin@apache.org>
2024-10-04 10:29:31 -07:00
ericholguin
6751bc15cc ux: Seamless Timeline
This PR is a ux change to make the header, tabbar, and post button disappear when the user scrolls.
The main tabbar is now an overlay which means it will display over views, this was needed in
order to get the timeline to extend behind it. However, this mean we must add bottom padding to any
view where the main tabbar is present to account for the overlap.

Changelog-Added: Disappearing header, tabbar, and post button on scroll

Signed-off-by: ericholguin <ericholguin@apache.org>
2024-10-01 17:32:56 -06:00
William Casarin
735fa97089 Merge remote-tracking branch 'github/translations'
Transifex (11):
      Translate Localizable.strings in th
      Translate Localizable.strings in th
      Translate Localizable.strings in th
      Translate Localizable.strings in de
      Translate Localizable.strings in zh_CN
      Translate Localizable.strings in zh_HK
      Translate Localizable.strings in zh_HK
      Translate Localizable.strings in zh_TW
      Translate Localizable.strings in de
      Translate Localizable.strings in de
      Translate Localizable.strings in de
2024-09-27 13:55:17 -07:00
William Casarin
314774f032 fixup: 128 instead of 500
500 is excessive

Signed-off-by: William Casarin <jb55@jb55.com>
2024-09-27 13:52:58 -07:00
William Casarin
262bbf26ea profiles: expand search results to 128
This should be plenty

Fixes: https://github.com/damus-io/damus/issues/2547
Changelog-Changed: Expanded profile search results to 128
Changelog-Fixed: Friend profiles will now more likely show up in profile search
Signed-off-by: William Casarin <jb55@jb55.com>
2024-09-27 13:51:08 -07:00
transifex-integration[bot]
cdf8d043c9 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-09-27 20:30:09 +00:00
transifex-integration[bot]
1eb7c94a5a Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-09-27 20:26:31 +00:00
William Casarin
5228d8cf4d Merge 'Add PR template with checklist #2548'
Daniel D’Aquino (1):
      Add PR template with checklist
2024-09-27 12:45:40 -07:00
William Casarin
782779f0d7 Merge 'v1.10.1 changelog #2494'
Daniel D’Aquino (1):
      v1.10.1 changelog
2024-09-27 12:44:21 -07:00
William Casarin
18ec8e6b6c Merge 'ui: add ndb search to universe view #2464'
William Casarin (3):
      search: use lazyvstack
      search: expand search results to 128

ericholguin (1):
      ui: add ndb search to universe view
2024-09-27 12:41:53 -07:00
William Casarin
7d82d8b76f search: expand search results to 128
This continues our hack due to the way the compiler bridges to static
sized arrays. yes its horrible. no i don't care.

Changelog-Changed: Expand nostrdb text search results to 128 items
Signed-off-by: William Casarin <jb55@jb55.com>
2024-09-27 12:37:53 -07:00
William Casarin
f957756df7 search: use lazyvstack
we're gonna need this when expanding search results

Changelog-Changed: Use LazyVStack in text search results
Signed-off-by: William Casarin <jb55@jb55.com>
2024-09-27 12:37:21 -07:00
Daniel D’Aquino
2cb0553723 Add PR template with checklist
This adds a PR template that will be applied to every new pull request,
to help both contributors and reviewers make sure that the contribution
guidelines are being met.

Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-09-25 12:29:16 -07:00
Daniel D’Aquino
8464e151cc v1.10.1 changelog
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-09-25 11:48:33 -07:00
Daniel D’Aquino
2da444e7c2 Merge branch 'release_1.10' 2024-09-25 11:19:38 -07:00
2a19d5d831 Add Apple translation popovers for notes for iOS 17.4+ and macOS 14.4+
Changelog-Added: Add Apple translation popovers for notes for iOS 17.4+ and macOS 14.4+
2024-09-23 20:14:31 -07:00
Daniel D’Aquino
f92509fddf Version bump to 1.10.1
This is needed because we already have a 1.10 build approved by Apple,
and they require a version number bump

Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-09-22 13:32:33 -07:00
ericholguin
62772615b6 ui: add ndb search to universe view
This PR adds the NDB search functionality from the pull down search in the
posting timeline to the universe view.

Changelog-Added: Added NDB search functionality to the universe view

Signed-off-by: ericholguin <ericholguin@apache.org>
2024-09-11 20:34:24 -06:00
transifex-integration[bot]
8c5b0ed5c4 Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-09-06 07:19:26 +00:00
transifex-integration[bot]
8481ab85de Translate Localizable.strings in zh_TW
100% translated source file: 'Localizable.strings'
on 'zh_TW'.
2024-09-01 08:22:33 +00:00
transifex-integration[bot]
881d3a3aa1 Translate Localizable.strings in zh_HK
100% translated source file: 'Localizable.strings'
on 'zh_HK'.
2024-09-01 08:17:37 +00:00
transifex-integration[bot]
878509090f Translate Localizable.strings in zh_HK
100% translated source file: 'Localizable.strings'
on 'zh_HK'.
2024-09-01 08:15:50 +00:00
transifex-integration[bot]
24657ecc75 Translate Localizable.strings in zh_CN
100% translated source file: 'Localizable.strings'
on 'zh_CN'.
2024-09-01 08:08:30 +00:00
transifex-integration[bot]
881ece214d Translate Localizable.strings in de
100% translated source file: 'Localizable.strings'
on 'de'.
2024-08-24 18:28:10 +00:00
transifex-integration[bot]
2519b0ee9f Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2024-08-08 02:50:07 +00:00
transifex-integration[bot]
ba1589e2e2 Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2024-08-08 02:49:58 +00:00
transifex-integration[bot]
e9a2473bad Translate Localizable.strings in th
100% translated source file: 'Localizable.strings'
on 'th'.
2024-08-08 02:47:04 +00:00
372 changed files with 22059 additions and 4655 deletions

52
.github/ISSUE_TEMPLATE/app_release.md vendored Normal file
View File

@@ -0,0 +1,52 @@
---
name: App release process
about: Begin preparing for a new app release
title: 'Release: '
labels: release-tasks
assignees: ''
---
A new version release. Please attempt to follow the release process steps below in the order they are shown.
## TestFlight release candidates
### Release candidate 1
**Version:** _[Enter full build information for the release candidate, including major and minor version number, build number, and commit hash]_
1. [ ] Merge in all needed changes to `master`
2. [ ] Check CI, make sure it is passing
3. [ ] Prepare preliminary changelog as a draft PR: _[Enter PR link to changelog here]_
4. [ ] Make a _release_ build and submit to the internal TestFlight group via our new Release candidate workflow in Xcode Cloud.
5. [ ] Prepare short screencast style video with main changes for the announcement
6. [ ] Publish release build to these TestFlight groups:
- [ ] Alpha testers group
- [ ] Translators group
- [ ] Purple group
7. [ ] Publish announcement on Nostr
_[Duplicate this release candidate section if there is more than one release candidate]_
## App Store release
1. [ ] Release candidate checks:
- [ ] Release candidate has been on Purple TestFlight for at least one week
- [ ] No blocker issues came from feedback from Purple users (double-check)
- [ ] Check with stakeholders
- [ ] Check with developers & product for any release showstoppers (e.g., critical newfound bugs)
2. [ ] Thorough check on release notes
3. [ ] Submit to App Store review (with manual publishing setting enabled)
4. [ ] Get App Store approval from Apple
5. [ ] Prepare announcement
7. [ ] Publish on the App Store and make announcement
8. [ ] Publish changelog and tag commit hash corresponding to the release
9. [ ] Perform a version bump on the repository, in preparation for the next release
## Notes/others
_Enter any relevant notes here_

37
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,37 @@
## Summary
_[Please provide a summary of the changes in this PR.]_
## Checklist
- [ ] I have read (or I am familiar with) the [Contribution Guidelines](../docs/CONTRIBUTING.md)
- [ ] I have tested the changes in this PR
- [ ] I have opened or referred to an existing github issue related to this change.
- [ ] My PR is either small, or I have split it into smaller logical commits that are easier to review
- [ ] I have added the signoff line to all my commits. See [Signing off your work](../docs/CONTRIBUTING.md#sign-your-work---the-developers-certificate-of-origin)
- [ ] I have added appropriate changelog entries for the changes in this PR. See [Adding changelog entries](../docs/CONTRIBUTING.md#add-changelog-changed-changelog-fixed-etc)
- [ ] I do not need to add a changelog entry. Reason: _[Please provide a reason]_
- [ ] I have added appropriate `Closes:` or `Fixes:` tags in the commit messages wherever applicable, or made sure those are not needed. See [Submitting patches](https://github.com/damus-io/damus/blob/master/docs/CONTRIBUTING.md#submitting-patches)
## Test report
_Please provide a test report for the changes in this PR. You can use the template below, but feel free to modify it as needed._
**Device:** _[Please specify the device you used for testing]_
**iOS:** _[Please specify the iOS version you used for testing]_
**Damus:** _[Please specify the Damus version or commit hash you used for testing]_
**Setup:** _[Please provide a brief description of the setup you used for testing, if applicable]_
**Steps:** _[Please provide a list of steps you took to test the changes in this PR]_
**Results:**
- [ ] PASS
- [ ] Partial PASS
- Details: _[Please provide details of the partial pass]_
## Other notes
_[Please provide any other information that you think is relevant to this PR.]_

5
ACKNOWLEDGEMENTS.md Normal file
View File

@@ -0,0 +1,5 @@
### Acknowledgements and licenses
1. This product contains code derived from [Nostr SDK iOS](https://github.com/nostr-sdk/nostr-sdk-ios). [License](https://github.com/nostr-sdk/nostr-sdk-ios/blob/40df800c6749d7ce0b6fd7328e76cbc0dc71c87b/LICENSE)
2. This product includes software developed by the "Marcin Krzyzanowski" (http://krzyzanowskim.com/). [License](https://github.com/krzyzanowskim/CryptoSwift/blob/e74bbbfbef939224b242ae7c342a90e60b88b5ce/LICENSE)

View File

@@ -1,3 +1,219 @@
## [1.13.1] - 2025-03-21
### Fixed
- Fixed an issue where threads would not load properly (Daniel DAquino)
[1.13.1]: https://github.com/damus-io/damus/releases/tag/v1.13.1
## [1.13] - 2025-03-14
### Added
- Added local persistence of note drafts (Daniel DAquino)
- Added user-friendly error view for errors around the app that would not fit in other places (Daniel DAquino)
- Coinos connection button in Wallet view (ericholguin)
- Added Alby Go to mobile wallets selection menu (Tomek ⚡ K)
- Minor accessibility improvements around picture editing and onboarding (Daniel DAquino)
- Profile image cropping tools (Daniel DAquino)
- Added Conversations tab to profiles (Terry Yiu)
- Added profile pictures to push notifications (William Casarin)
### Changed
- Don't show reposts for the same note more than once in your home feed (William Casarin)
- Improved profile image bandwidth optimization (Daniel DAquino)
- Improved reliability of picture selector (Daniel DAquino)
- Changed spaces to newlines in new posts to provide cleaner separation between text, uploaded media, and quoted notes (Terry Yiu)
### Fixed
- Fixed issue where some push notifications would not open in the app and leave users confused (Daniel DAquino)
- Fixed issue where app would need a restart for new NWC wallets to work (Daniel DAquino)
- Fixed overly sensitive horizontal swipe on thread chat view (Daniel DAquino)
- Trim whitespaces from Lightning addresses (Terry Yiu)
- Fixed translation export script by upgrading nostr-sdk-swift dependency to support Mac Catalyst (Terry Yiu)
- Fixed issue where users continue to receive push notifications after logout (Daniel DAquino)
- Fixed an issue where events on a thread view would occasionally disappear (Daniel DAquino)
- Improved robustness of the URL handler (Daniel DAquino)
- Translate notes even if they are in a preferred language but not the current language as that is what users expect (Terry Yiu)
- Cancel ongoing uploading operations after the user cancels the post (Swift Coder)
- Fixed link and photo sharing support on macOS (Swift Coder)
- Fix bug where profile view was showing more than just the notes and replies on the notes / notes & replies tabs (Terry Yiu)
- Fixed reposts banner to be localizable (Terry Yiu)
### Removed
- Removed language filtering from Universe feed because language detection can be inaccurate (Terry Yiu)
- Removed mystery tabs meant to fix tab switching bug that no longer exists (Terry Yiu)
[1.13](https://github.com/damus-io/damus/releases/tag/v1.13): https://github.com/damus-io/damus/releases/tag/v1.13
## [1.12.3] - 2025-02-06
### Added
- Purple members who have been active for more than a year now get a special badge (Daniel DAquino)
### Changed
- Improved clarity of the mute button to indicate it can be used for blocking a user (Daniel DAquino)
- Made the microphone access request message more clear to users (Daniel DAquino)
[v1.12.3]: https://github.com/damus-io/damus/releases/tag/v1.12.3
## [1.12](https://github.com/damus-io/damus/releases/tag/v1.12) - 2024-12-20
### Added
- Render Gif and video files while composing posts (Swift Coder)
- Add profile info text in stretchable banner with follow button (Swift Coder)
- Paste Gif image similar to jpeg and png files (Swift Coder)
### Changed
- Improved UX around the label for searching words (Daniel DAquino)
- Improved accessibility support on some elements (Daniel DAquino)
### Fixed
- Fixed issue where the "next" button would appear hidden and hard to click on the create account view (Daniel DAquino)
- Fix non scrollable wallet screen (Swift Coder)
- Fixed suggested users category titles to be localizable (Terry Yiu)
- Fixed GradientFollowButton to have consistent width and autoscale text limited to 1 line (Terry Yiu)
- Fixed right-to-left localization issues (Terry Yiu)
- Fixed AddMuteItemView to trim leading and trailing whitespaces from mute text and disallow adding text with only whitespaces (Terry Yiu)
- Fixed SideMenuView text to autoscale and limit to 1 line (Terry Yiu)
- Fixed an issue where a profile would need to be input twice in the search to be found (Daniel DAquino)
- Fixed non-breaking spaces in localized strings (Terry Yiu)
- Fixed localization issue on Add mute item button (Terry Yiu)
- Replace non-breaking spaces with regular spaces as Apple's NSLocalizedString macro does not seem to work with it (Terry Yiu)
- Fixed localization issues in RelayConfigView (Terry Yiu)
- Fix duplicate uploads (Swift Coder)
- Remove duplicate pubkey from Follow Suggestion list (Swift Coder)
- Fix Page control indicator (Swift Coder)
- Fix damus sharing issues (Swift Coder)
- Fixed issue where banner edit button is unclickable (Daniel DAquino)
- Handle empty notification pages by displaying suitable text (Swift Coder)
[v1.12](https://github.com/damus-io/damus/releases/tag/v1.12): [https://github.com/damus-io/damus/releases/tag/v1.12]
## [v1.11(10)](https://github.com/damus-io/damus/releases/tag/v1.11-10) - 2024-11-18
### Added
- Add Damus Share Feature (Swift)
- Added new easy to use video controls for full screen video (Daniel DAquino)
- Add Edit, Share, and Tap-gesture in Profile pic image viewer (Swift Coder)
- Disappearing header, tabbar, and post button on scroll (ericholguin)
- Add Apple translation popovers for notes for iOS 17.4+ and macOS 14.4+ (Terry Yiu)
- Added NDB search functionality to the universe view (ericholguin)
- Added mute button to ProfileActionSheet (chungwwei)
- Added mute action to selected text menu (ericholguin)
- Added support for pasting images from the clipboard to the post composer (Swift Coder)
### Changed
- Improved image carousel image fill behavior (Daniel DAquino)
- Improved video syncing and bandwidth usage when switching between timeline video and full screen mode (Daniel DAquino)
- Swipe to dismiss on full screen carousel now shows an opacity effect for improved UX (Daniel DAquino)
- Removed event contents from full screen media carousel for cleaner view (Daniel DAquino)
- Add share button for images on full screen image carousel view (Swift)
- Changed boldness of font in side menu labels. (ericholguin)
- Changed search notes button with searched keyword (ericholguin)
- Changed opacity of tabbar and post button (ericholguin)
- Allow multiple images to be uploaded at the same time (swiftcoder) (William Casarin)
- Changed side menu design (ericholguin)
- Truncate fulltext search results (William Casarin)
- Expanded profile search results to 128 (William Casarin)
- Expand nostrdb text search results to 128 items (William Casarin)
- Use LazyVStack in text search results (William Casarin)
### Fixed
- Fixed missing tab bar on navigation (Swift Coder)
- Fixed some issues where QR code would not work, and improved UX (Daniel DAquino)
- Fixed iOS 18 gesture issues that would take user to the thread view when clicking on a video or unmuting it (Daniel DAquino)
- Fixed several issues that would cause video to automatically play or pause incorrectly (Daniel DAquino)
- Fixed issue where full screen video would disappear when going to landscape mode (Daniel DAquino)
- Fixed portrait video size on full screen carousel (Daniel DAquino)
- Fix avatar image on qrcode view (Swift Coder)
- Fix banner image upload (Swift Coder)
- Fix dismiss button visibility (Swift Coder)
- Fix quote repost counting (William Casarin)
- Fixed overlapping text in Universe View (ericholguin)
- Fixed localization issues and exported strings (Terry Yiu)
- Fix sensitive long-press gesture on event chat bubble in iOS 18 (Daniel DAquino)
- Fixed bottom padding for tabbar (ericholguin)
- Fixed localization build failures (Terry Yiu)
- Fixed back nav button placement in profile edit view (ericholguin)
- Friend profiles will now more likely show up in profile search (William Casarin)
- Fix broken QR code scanner and fix landscape mode (Terry Yiu)
[1.11(10)](https://github.com/damus-io/damus/releases/tag/v1.11-10): https://github.com/damus-io/damus/releases/tag/v1.11-10
## [1.10.1] - 2024-09-22
### Added
- Push notification support (Daniel DAquino)
- Added profile edit safe guards (Eric Holguin)
- Tor relay icon (ericholguin)
- Add highlighter for web pages (Daniel DAquino)
- Add support for adding comments when creating a highlight (Daniel DAquino)
- Add support for rendering highlights with comments (Daniel DAquino)
- Ability to create highlights (ericholguin)
- Highlights (NIP-84) (ericholguin)
- Revamp emoji picker to be less error-prone and add search, frequently used, and multiple skin tone support capabilities (Terry Yiu)
### Changed
- Improve notification view filtering UX (Daniel DAquino)
- Improve visibility of friends filter button (Daniel DAquino)
- Changed the default banner from ostriches to damoose (Eric Holguin)
- Changed image and banner url text fields to new sheet view (Eric Holguin)
- Onboarding design (ericholguin)
### Fixed
- Fix items that became unclickable on iOS 18 (Daniel DAquino)
- Fix many reconnection issues (William Casarin)
- Fixed issue where theme would be changed to black and can't be switched back on iOS 18 (cr0bar)
- Fixed some scenarios where the contact list would never be saved locally and cause issues when switching relays. (Daniel DAquino)
- Fix albyhub zaps not appearing (William Casarin)
- Fix inadvertent escape from mention suggestion menu when typing a space character (Daniel DAquino)
- Fix profile view toolbar alignment bug in iOS 18 (Terry Yiu)
- Create Account model now uses correct metadata (ericholguin)
- Restore localization for custom tabs (William Casarin)
- Fix iOS 18 reflection runtime error for custom picker (William Casarin)
[1.10.1]: https://github.com/damus-io/damus/releases/tag/v1.10.1
## [1.9.1 (4)] - 2024-08-13
### Fixed
- Fix crash when viewing notes with invalid image dimension metadata (Daniel DAquino)
[1.9.1 (4)]: https://github.com/damus-io/damus/releases/tag/v1.9.1-4
## [1.9 (14)] - 2024-07-14
### Added

View File

@@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.usernotifications.communication</key>
<true/>
<key>com.apple.developer.kernel.extended-virtual-addressing</key>
<true/>
<key>com.apple.security.app-sandbox</key>

View File

@@ -18,7 +18,7 @@ struct NotificationExtensionState: HeadlessDamusState {
let lnurls: LNUrls
init?() {
guard let ndb = try? Ndb(owns_db_file: false) else { return nil }
guard let ndb = Ndb(owns_db_file: false) else { return nil }
self.ndb = ndb
guard let keypair = get_saved_keypair() else { return nil }

View File

@@ -5,15 +5,32 @@
// Created by Daniel DAquino on 2023-11-10.
//
import Kingfisher
import ImageIO
import UserNotifications
import Foundation
import UniformTypeIdentifiers
import Intents
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
private func configureKingfisherCache() {
guard let groupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: Constants.DAMUS_APP_GROUP_IDENTIFIER) else {
return
}
let cachePath = groupURL.appendingPathComponent(Constants.IMAGE_CACHE_DIRNAME)
if let cache = try? ImageCache(name: "sharedCache", cacheDirectoryURL: cachePath) {
KingfisherManager.shared.cache = cache
}
}
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
configureKingfisherCache()
self.contentHandler = contentHandler
guard let nostr_event_json = request.content.userInfo["nostr_event"] as? String,
@@ -40,9 +57,16 @@ class NotificationService: UNNotificationServiceExtension {
return
}
let txn = state.ndb.lookup_profile(nostr_event.pubkey)
let profile = txn?.unsafeUnownedValue?.profile
let name = Profile.displayName(profile: profile, pubkey: nostr_event.pubkey).displayName
let sender_profile = {
let txn = state.ndb.lookup_profile(nostr_event.pubkey)
let profile = txn?.unsafeUnownedValue?.profile
let picture = ((profile?.picture.map { URL(string: $0) }) ?? URL(string: robohash(nostr_event.pubkey)))!
return ProfileBuf(picture: picture,
name: profile?.name,
display_name: profile?.display_name,
nip05: profile?.nip05)
}()
let sender_pubkey = nostr_event.pubkey
// Don't show notification details that match mute list.
// TODO: Remove this code block once we get notification suppression entitlement from Apple. It will be covered by the `guard should_display_notification` block
@@ -56,7 +80,7 @@ class NotificationService: UNNotificationServiceExtension {
contentHandler(content)
return
}
guard should_display_notification(state: state, event: nostr_event, mode: .push) else {
Log.debug("should_display_notification failed", for: .push_notifications)
// We should not display notification for this event. Suppress notification.
@@ -65,7 +89,7 @@ class NotificationService: UNNotificationServiceExtension {
contentHandler(request.content)
return
}
guard let notification_object = generate_local_notification_object(from: nostr_event, state: state) else {
Log.debug("generate_local_notification_object failed", for: .push_notifications)
// We could not process this notification. Probably an unsupported nostr event kind. Suppress.
@@ -74,15 +98,58 @@ class NotificationService: UNNotificationServiceExtension {
contentHandler(request.content)
return
}
Task {
guard let (improvedContent, _) = await NotificationFormatter.shared.format_message(displayName: name, notify: notification_object, state: state) else {
let sender_dn = DisplayName(name: sender_profile.name, display_name: sender_profile.display_name, pubkey: sender_pubkey)
guard let (improvedContent, _) = await NotificationFormatter.shared.format_message(displayName: sender_dn.displayName, notify: notification_object, state: state) else {
Log.debug("NotificationFormatter.format_message failed", for: .push_notifications)
return
}
contentHandler(improvedContent)
do {
var options: [AnyHashable: Any] = [:]
if let imageSource = CGImageSourceCreateWithURL(sender_profile.picture as CFURL, nil),
let uti = CGImageSourceGetType(imageSource) {
options[UNNotificationAttachmentOptionsTypeHintKey] = uti
}
let attachment = try UNNotificationAttachment(identifier: sender_profile.picture.absoluteString, url: sender_profile.picture, options: options)
improvedContent.attachments = [attachment]
} catch {
Log.error("failed to get notification attachment: %s", for: .push_notifications, error.localizedDescription)
}
let kind = nostr_event.known_kind
// these aren't supported yet
if !(kind == .text || kind == .dm) {
contentHandler(improvedContent)
return
}
// rich communication notifications for kind1, dms, etc
let message_intent = await message_intent_from_note(ndb: state.ndb,
sender_profile: sender_profile,
content: improvedContent.body,
note: nostr_event,
our_pubkey: state.keypair.pubkey)
improvedContent.threadIdentifier = nostr_event.thread_id().hex()
improvedContent.categoryIdentifier = "COMMUNICATION"
let interaction = INInteraction(intent: message_intent, response: nil)
interaction.direction = .incoming
do {
try await interaction.donate()
let updated = try improvedContent.updating(from: message_intent)
contentHandler(updated)
} catch {
Log.error("failed to donate interaction: %s", for: .push_notifications, error.localizedDescription)
contentHandler(improvedContent)
}
}
}
@@ -95,3 +162,162 @@ class NotificationService: UNNotificationServiceExtension {
}
}
struct ProfileBuf {
let picture: URL
let name: String?
let display_name: String?
let nip05: String?
}
func message_intent_from_note(ndb: Ndb, sender_profile: ProfileBuf, content: String, note: NdbNote, our_pubkey: Pubkey) async -> INSendMessageIntent {
let sender_pk = note.pubkey
let sender = await profile_to_inperson(name: sender_profile.name,
display_name: sender_profile.display_name,
picture: sender_profile.picture.absoluteString,
nip05: sender_profile.nip05,
pubkey: sender_pk,
our_pubkey: our_pubkey)
let conversationIdentifier = note.thread_id().hex()
var recipients: [INPerson] = []
var pks: [Pubkey] = []
let meta = INSendMessageIntentDonationMetadata()
// gather recipients
if let recipient_note_id = note.direct_replies() {
let replying_to = ndb.lookup_note(recipient_note_id)
if let replying_to_pk = replying_to?.unsafeUnownedValue?.pubkey {
meta.isReplyToCurrentUser = replying_to_pk == our_pubkey
if replying_to_pk != sender_pk {
// we push the actual person being replied to first
pks.append(replying_to_pk)
}
}
}
let pubkeys = Array(note.referenced_pubkeys)
meta.recipientCount = pubkeys.count
if pubkeys.contains(sender_pk) {
meta.recipientCount -= 1
}
for pk in pubkeys.prefix(3) {
if pk == sender_pk || pks.contains(pk) {
continue
}
if !meta.isReplyToCurrentUser && pk == our_pubkey {
meta.mentionsCurrentUser = true
}
pks.append(pk)
}
for pk in pks {
let recipient = await pubkey_to_inperson(ndb: ndb, pubkey: pk, our_pubkey: our_pubkey)
recipients.append(recipient)
}
// we enable default formatting this way
var groupName = INSpeakableString(spokenPhrase: "")
// otherwise we just say its a DM
if note.known_kind == .dm {
groupName = INSpeakableString(spokenPhrase: "DM")
}
let intent = INSendMessageIntent(recipients: recipients,
outgoingMessageType: .outgoingMessageText,
content: content,
speakableGroupName: groupName,
conversationIdentifier: conversationIdentifier,
serviceName: "kind\(note.kind)",
sender: sender,
attachments: nil)
intent.donationMetadata = meta
// this is needed for recipients > 0
if let img = sender.image {
intent.setImage(img, forParameterNamed: \.speakableGroupName)
}
return intent
}
func pubkey_to_inperson(ndb: Ndb, pubkey: Pubkey, our_pubkey: Pubkey) async -> INPerson {
let profile_txn = ndb.lookup_profile(pubkey)
let profile = profile_txn?.unsafeUnownedValue?.profile
let name = profile?.name
let display_name = profile?.display_name
let nip05 = profile?.nip05
let picture = profile?.picture
return await profile_to_inperson(name: name,
display_name: display_name,
picture: picture,
nip05: nip05,
pubkey: pubkey,
our_pubkey: our_pubkey)
}
func fetch_pfp(picture: URL) async throws -> RetrieveImageResult {
try await withCheckedThrowingContinuation { continuation in
KingfisherManager.shared.retrieveImage(with: Kingfisher.ImageResource(downloadURL: picture)) { result in
switch result {
case .success(let img):
continuation.resume(returning: img)
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
func profile_to_inperson(name: String?, display_name: String?, picture: String?, nip05: String?, pubkey: Pubkey, our_pubkey: Pubkey) async -> INPerson {
let npub = pubkey.npub
let handle = INPersonHandle(value: npub, type: .unknown)
var aliases: [INPersonHandle] = []
if let nip05 {
aliases.append(INPersonHandle(value: nip05, type: .emailAddress))
}
let nostrName = DisplayName(name: name, display_name: display_name, pubkey: pubkey)
let nameComponents = nostrName.nameComponents()
let displayName = nostrName.displayName
let contactIdentifier = npub
let customIdentifier = npub
let suggestionType = INPersonSuggestionType.socialProfile
var image: INImage? = nil
if let picture,
let url = URL(string: picture),
let img = try? await fetch_pfp(picture: url),
let imgdata = img.data()
{
image = INImage(imageData: imgdata)
} else {
Log.error("Failed to fetch pfp (%s) for %s", for: .push_notifications, picture ?? "nil", displayName)
}
let person = INPerson(personHandle: handle,
nameComponents: nameComponents,
displayName: displayName,
image: image,
contactIdentifier: contactIdentifier,
customIdentifier: customIdentifier,
isMe: pubkey == our_pubkey,
suggestionType: suggestionType
)
return person
}
func robohash(_ pk: Pubkey) -> String {
return "https://robohash.org/" + pk.hex()
}

View File

@@ -1,3 +1,32 @@
dependencies: [
.Package(url: "https://github.com/jb55/secp256k1.swift.git", branch: "main")
]
// swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "damus",
platforms: [
.iOS(.v16),
.macOS(.v12)
],
products: [
.library(
name: "damus",
targets: ["damus"]),
],
dependencies: [
.package(url: "https://github.com/jb55/secp256k1.swift.git", branch: "main")
],
targets: [
.target(
name: "damus",
dependencies: [
.product(name: "secp256k1", package: "secp256k1.swift")
],
path: "damus"),
.testTarget(
name: "damusTests",
dependencies: ["damus"],
path: "damusTests"),
]
)

View File

@@ -8,7 +8,7 @@ A twitter-like [nostr][nostr] client for iPhone, iPad and MacOS.
[nostr]: https://github.com/fiatjaf/nostr
## How is Damus better than twitter?
## How is Damus better than X/Twitter?
There are no toxic algorithms.\
You can send or receive zaps (satoshis) without asking for permission.\
[There is no central database](https://fiatjaf.com/nostr.html). Therefore, Damus is censorship resistant.\

1
TODO
View File

@@ -0,0 +1 @@
Fix q tags

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,29 @@
{
"originHash" : "babaf4d5748afecf49bbb702530d8e9576460692f478b0a50ee43195dd4440e2",
"originHash" : "06318d35ee2e6bd681b95591e67da33a9461b48a3c652e58bd9d1a6f0d82bdac",
"pins" : [
{
"identity" : "codescanner",
"kind" : "remoteSourceControl",
"location" : "https://github.com/twostraws/CodeScanner.git",
"state" : {
"revision" : "9fa582f4b36c69c2a55bff5fb3377eb170ae273c"
}
},
{
"identity" : "cryptoswift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/krzyzanowskim/CryptoSwift.git",
"state" : {
"revision" : "e74bbbfbef939224b242ae7c342a90e60b88b5ce"
}
},
{
"identity" : "emojikit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/tyiu/EmojiKit",
"state" : {
"revision" : "05805f72d63a6d6a2d7dc7fe14abd37c1317b11a",
"version" : "0.1.2"
"revision" : "47a4b1402de26be0299dcb4d667c1faaf21a7874",
"version" : "0.2.0"
}
},
{
@@ -15,8 +31,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/tyiu/EmojiPicker.git",
"state" : {
"revision" : "0c28b4a1a6b8840cf2580bda59517f6d0a733dc8",
"version" : "0.1.1"
"revision" : "3f48903721eae223238ff0af17c22d6373d33813",
"version" : "0.2.0"
}
},
{
@@ -33,8 +49,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/onevcat/Kingfisher",
"state" : {
"revision" : "415b1d97fb38bda1e5a6b2dde63354720832110b",
"version" : "7.6.1"
"revision" : "4c6b067f96953ee19526e49e4189403a2be21fb3",
"version" : "8.3.1"
}
},
{
@@ -89,13 +105,20 @@
"version" : "0.1.2"
}
},
{
"identity" : "swiftycrop",
"kind" : "remoteSourceControl",
"location" : "https://github.com/benedom/SwiftyCrop",
"state" : {
"revision" : "454d0a0d4faf6f3a19c8d817ab9d7d27524bd79f"
}
},
{
"identity" : "swipeactions",
"kind" : "remoteSourceControl",
"location" : "https://github.com/aheze/SwipeActions",
"location" : "https://github.com/damus-io/SwipeActions.git",
"state" : {
"revision" : "41e6f6dce02d8cfa164f8c5461a41340850ca3ab",
"version" : "1.1.0"
"revision" : "33d99756c3112e1a07c1732e3cddc5ad5bd0c5f4"
}
}
],

View File

@@ -40,7 +40,7 @@
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "YES">
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4CE6DEFC27F7A08200C66700"

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 118 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

Before

Width:  |  Height:  |  Size: 511 KiB

After

Width:  |  Height:  |  Size: 511 KiB

View File

Before

Width:  |  Height:  |  Size: 187 KiB

After

Width:  |  Height:  |  Size: 187 KiB

View File

Before

Width:  |  Height:  |  Size: 122 KiB

After

Width:  |  Height:  |  Size: 122 KiB

View File

Before

Width:  |  Height:  |  Size: 146 KiB

After

Width:  |  Height:  |  Size: 146 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 547 KiB

After

Width:  |  Height:  |  Size: 547 KiB

View File

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 124 KiB

View File

@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "alby.svg",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "alby.svg",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "alby.svg",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 300 KiB

After

Width:  |  Height:  |  Size: 300 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 215 KiB

After

Width:  |  Height:  |  Size: 215 KiB

View File

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 61 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -1,7 +1,7 @@
{
"images" : [
{
"filename" : "profile-banner.jpeg",
"filename" : "coinos.png",
"idiom" : "universal"
}
],

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

Before

Width:  |  Height:  |  Size: 176 KiB

After

Width:  |  Height:  |  Size: 176 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 78 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 290 KiB

View File

@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "alby-go.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -1,23 +0,0 @@
{
"images": [
{
"filename": "alby.svg",
"idiom": "universal",
"scale": "1x"
},
{
"idiom": "universal",
"scale": "2x",
"filename": "alby.svg"
},
{
"idiom": "universal",
"scale": "3x",
"filename": "alby.svg"
}
],
"info": {
"author": "xcode",
"version": 1
}
}

View File

Before

Width:  |  Height:  |  Size: 216 B

After

Width:  |  Height:  |  Size: 216 B

View File

@@ -46,7 +46,6 @@ struct CustomPicker<SelectionValue: Hashable>: View {
.accentColor(tag == selection ? textColor() : .gray)
}
}
.background(Color(UIColor.systemBackground))
}
func textColor() -> Color {

View File

@@ -20,6 +20,7 @@ struct DamusBackground: View {
.resizable()
.frame(maxWidth: .infinity, maxHeight: maxHeight, alignment: .center)
.ignoresSafeArea()
.accessibilityHidden(true)
}
}

View File

@@ -1,15 +0,0 @@
//
// MutinyGradient.swift
// damus
//
// Created by eric on 3/9/24.
//
import SwiftUI
fileprivate let mutiny_grad_c1 = hex_col(r: 39, g: 95, b: 161)
fileprivate let mutiny_grad_c2 = hex_col(r: 13, g: 33, b: 56)
fileprivate let mutiny_grad = [mutiny_grad_c2, mutiny_grad_c1]
let MutinyGradient: LinearGradient =
LinearGradient(colors: mutiny_grad, startPoint: .top, endPoint: .bottom)

View File

@@ -7,6 +7,7 @@
import SwiftUI
import Kingfisher
import Combine
// TODO: all this ShareSheet complexity can be replaced with ShareLink once we update to iOS 16
struct ShareSheet: UIViewControllerRepresentable {
@@ -95,64 +96,203 @@ enum ImageShape {
}
}
/// The `CarouselModel` helps `ImageCarousel` with some state management logic, keeping track of media sizes, and the ideal display size
///
/// This model is necessary because the state management logic required to keep track of media sizes for each one of the carousel items,
/// and the ideal display size at each moment is not a trivial task.
///
/// The rules for the media fill are as follows:
/// 1. The media item should generally have a width that completely fills the width of its parent view
/// 2. The height of the carousel should be adjusted accordingly
/// 3. The only exception to rules 1 and 2 is when the total height would be 20% larger than the height of the device
/// 4. If none of the above can be computed (e.g. due to missing information), default to a reasonable height, where the media item will fit into.
///
/// ## Usage notes
///
/// The view is has the following state management responsibilities:
/// 1. Watching the size of the images (via the `.observe_image_size` modifier)
/// 2. Notifying this class of geometry reader changes, by setting `geo_size`
///
/// ## Implementation notes
///
/// This class is organized in a way to reduce stateful behavior and the transiency bugs it can cause.
///
/// This is accomplished through the following pattern:
/// 1. The `current_item_fill` is a published property so that any updates instantly re-render the view
/// 2. However, `current_item_fill` has a mathematical dependency on other members of this class
/// 3. Therefore, the members on which the fill property depends on all have `didSet` observers that will cause the `current_item_fill` to be recalculated and published.
///
/// This pattern helps ensure that the state is always consistent and that the view is always up-to-date.
///
/// This class is marked as `@MainActor` since most of its properties are published and should be accessed from the main thread to avoid inconsistent SwiftUI state during renders
@MainActor
class CarouselModel: ObservableObject {
var current_url: URL?
var fillHeight: CGFloat
var maxHeight: CGFloat
var firstImageHeight: CGFloat?
// MARK: Immutable object attributes
// These are some attributes that are not expected to change throughout the lifecycle of this object
// These should not be modified after initialization to avoid state inconsistency
/// The state of the app
let damus_state: DamusState
/// All urls in the carousel
let urls: [MediaUrl]
/// The default fill height for the carousel, if we cannot calculate a more appropriate height
/// **Usage note:** Default to this when `current_item_fill` is nil
let default_fill_height: CGFloat
/// The maximum height for any carousel item
let max_height: CGFloat
// MARK: Miscellaneous
/// Holds items that allows us to cancel video size observers during de-initialization
private var all_cancellables: [AnyCancellable] = []
// MARK: State management properties
/// Properties relevant to state management.
/// These should be made into computed/functional properties when possible to avoid stateful behavior
/// When that is not possible (e.g. when dealing with an observed published property), establish its mathematical dependencies,
/// and use `didSet` observers to ensure that the state is always re-computed when necessary.
@Published var open_sheet: Bool
@Published var selectedIndex: Int
@Published var video_size: CGSize?
@Published var image_fill: ImageFill?
/// Stores information about the size of each media item in `urls`.
/// **Usage note:** The view is responsible for setting the size of image urls
var media_size_information: [URL: CGSize] {
didSet {
guard let current_url else { return }
// Upon updating information, update the carousel fill size if the size for the current url has changed
if oldValue[current_url] != media_size_information[current_url] {
self.refresh_current_item_fill()
}
}
}
/// Stores information about the geometry reader
/// **Usage note:** The view is responsible for setting this value
var geo_size: CGSize? {
didSet { self.refresh_current_item_fill() }
}
/// The index of the currently selected item
/// **Usage note:** The view is responsible for setting this value
@Published var selectedIndex: Int {
didSet { self.refresh_current_item_fill() }
}
/// The current fill for the media item.
/// **Usage note:** This property is read-only and should not be set directly. Update `selectedIndex` to update the current item being viewed.
var current_url: URL? {
return urls[safe: selectedIndex]?.url
}
/// Holds the ideal fill dimensions for the current item.
/// **Usage note:** This property is automatically updated when other properties are set, and should not be set directly
/// **Implementation note:** This property is mathematically dependent on geo_size, media_size_information, and `selectedIndex`,
/// and is automatically updated upon changes to these properties.
@Published private(set) var current_item_fill: ImageFill?
// MARK: Initialization and de-initialization
init(image_fill: ImageFill?) {
self.current_url = nil
self.fillHeight = 350
self.maxHeight = UIScreen.main.bounds.height * 1.2 // 1.2
self.firstImageHeight = nil
self.open_sheet = false
/// Initializes the `CarouselModel` with the given `DamusState` and `MediaUrl` array
init(damus_state: DamusState, urls: [MediaUrl]) {
// Immutable object attributes
self.damus_state = damus_state
self.urls = urls
self.default_fill_height = 350
self.max_height = UIScreen.main.bounds.height * 1.2 // 1.2
// State management properties
self.selectedIndex = 0
self.video_size = nil
self.image_fill = image_fill
self.current_item_fill = nil
self.geo_size = nil
self.media_size_information = [:]
// Setup the rest of the state management logic
self.observe_video_sizes()
Task {
self.refresh_current_item_fill()
}
}
/// This private function observes the video sizes for all videos
private func observe_video_sizes() {
for media_url in urls {
switch media_url {
case .video(let url):
let video_player = damus_state.video.get_player(for: url)
if let video_size = video_player.video_size {
self.media_size_information[url] = video_size // Set the initial size if available
}
let observer_cancellable = video_player.$video_size.sink(receiveValue: { new_size in
self.media_size_information[url] = new_size // Update the size when it changes
})
all_cancellables.append(observer_cancellable) // Store the cancellable to cancel it later
case .image(_):
break; // Observing an image size needs to be done on the view directly, through the `.observe_image_size` modifier
}
}
}
deinit {
for cancellable_item in all_cancellables {
cancellable_item.cancel()
}
}
// MARK: State management and logic
/// This function refreshes the current item fill based on the current state of the model
/// **Usage note:** This is private, do not call this directly from outside the class.
/// **Implementation note:** This should be called using `didSet` observers on properties that affect the fill
private func refresh_current_item_fill() {
if let current_url,
let item_size = self.media_size_information[current_url],
let geo_size {
self.current_item_fill = ImageFill.calculate_image_fill(
geo_size: geo_size,
img_size: item_size,
maxHeight: self.max_height,
fillHeight: self.default_fill_height
)
}
else {
self.current_item_fill = nil // Not enough information to compute the proper fill. Default to nil
}
}
}
// MARK: - Image Carousel
/// A carousel that displays images and videos
///
/// ## Implementation notes
///
/// - State management logic is mostly handled by `CarouselModel`, as it is complex, and becomes difficult to manage in a view
///
@MainActor
struct ImageCarousel<Content: View>: View {
var urls: [MediaUrl]
/// The event id of the note that this carousel is displaying
let evid: NoteId
let state: DamusState
/// The model that holds information and state of this carousel
/// This is observed to update the view when the model changes
@ObservedObject var model: CarouselModel
let content: ((_ dismiss: @escaping (() -> Void)) -> Content)?
init(state: DamusState, evid: NoteId, urls: [MediaUrl]) {
self.urls = urls
self.evid = evid
self.state = state
let media_model = state.events.get_cache_data(evid).media_metadata_model
self._model = ObservedObject(initialValue: CarouselModel(image_fill: media_model.fill))
self._model = ObservedObject(initialValue: CarouselModel(damus_state: state, urls: urls))
self.content = nil
}
init(state: DamusState, evid: NoteId, urls: [MediaUrl], @ViewBuilder content: @escaping (_ dismiss: @escaping (() -> Void)) -> Content) {
self.urls = urls
self.evid = evid
self.state = state
let media_model = state.events.get_cache_data(evid).media_metadata_model
self._model = ObservedObject(initialValue: CarouselModel(image_fill: media_model.fill))
self._model = ObservedObject(initialValue: CarouselModel(damus_state: state, urls: urls))
self.content = content
}
var filling: Bool {
model.image_fill?.filling == true
model.current_item_fill?.filling == true
}
var height: CGFloat {
model.firstImageHeight ?? model.image_fill?.height ?? model.fillHeight
// Use the calculated fill height if available, otherwise use the default fill height
model.current_item_fill?.height ?? model.default_fill_height
}
func Placeholder(url: URL, geo_size: CGSize, num_urls: Int) -> some View {
@@ -160,7 +300,7 @@ struct ImageCarousel<Content: View>: View {
if num_urls > 1 {
// jb55: quick hack since carousel with multiple images looks horrible with blurhash background
Color.clear
} else if let meta = state.events.lookup_img_metadata(url: url),
} else if let meta = model.damus_state.events.lookup_img_metadata(url: url),
case .processed(let blurhash) = meta.state {
Image(uiImage: blurhash)
.resizable()
@@ -169,12 +309,6 @@ struct ImageCarousel<Content: View>: View {
Color.clear
}
}
.onAppear {
if self.model.image_fill == nil, let size = state.video.size_for_url(url) {
let fill = ImageFill.calculate_image_fill(geo_size: geo_size, img_size: size, maxHeight: model.maxHeight, fillHeight: model.fillHeight)
self.model.image_fill = fill
}
}
}
func Media(geo: GeometryProxy, url: MediaUrl, index: Int) -> some View {
@@ -183,24 +317,17 @@ struct ImageCarousel<Content: View>: View {
case .image(let url):
Img(geo: geo, url: url, index: index)
.onTapGesture {
model.open_sheet = true
present(full_screen_item: .full_screen_carousel(urls: model.urls, selectedIndex: $model.selectedIndex))
}
case .video(let url):
DamusVideoPlayer(url: url, video_size: $model.video_size, controller: state.video, style: .preview(on_tap: { model.open_sheet = true }))
.onChange(of: model.video_size) { size in
guard let size else { return }
let fill = ImageFill.calculate_image_fill(geo_size: geo.size, img_size: size, maxHeight: model.maxHeight, fillHeight: model.fillHeight)
print("video_size changed \(size)")
if self.model.image_fill == nil {
print("video_size firstImageHeight \(fill.height)")
self.model.firstImageHeight = fill.height
state.events.get_cache_data(evid).media_metadata_model.fill = fill
}
self.model.image_fill = fill
}
let video_model = model.damus_state.video.get_player(for: url)
DamusVideoPlayerView(
model: video_model,
coordinator: model.damus_state.video,
style: .preview(on_tap: {
present(full_screen_item: .full_screen_carousel(urls: model.urls, selectedIndex: $model.selectedIndex))
})
)
}
}
}
@@ -209,31 +336,18 @@ struct ImageCarousel<Content: View>: View {
KFAnimatedImage(url)
.callbackQueue(.dispatch(.global(qos:.background)))
.backgroundDecode(true)
.imageContext(.note, disable_animation: state.settings.disable_animation)
.imageContext(.note, disable_animation: model.damus_state.settings.disable_animation)
.image_fade(duration: 0.25)
.cancelOnDisappear(true)
.configure { view in
view.framePreloadCount = 3
}
.imageFill(for: geo.size, max: model.maxHeight, fill: model.fillHeight) { fill in
state.events.get_cache_data(evid).media_metadata_model.fill = fill
// blur hash can be discarded when we have the url
// NOTE: this is the wrong place for this... we need to remove
// it when the image is loaded in memory. This may happen
// earlier than this (by the preloader, etc)
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
state.events.lookup_img_metadata(url: url)?.state = .not_needed
}
self.model.image_fill = fill
if index == 0 {
self.model.firstImageHeight = fill.height
//maxHeight = firstImageHeight ?? maxHeight
} else {
//maxHeight = firstImageHeight ?? fill.height
}
}
.observe_image_size(size_changed: { size in
// Observe the image size to update the model when the size changes, so we can calculate the fill
model.media_size_information[url] = size
})
.background {
Placeholder(url: url, geo_size: geo.size, num_urls: urls.count)
Placeholder(url: url, geo_size: geo.size, num_urls: model.urls.count)
}
.aspectRatio(contentMode: filling ? .fill : .fit)
.kfClickable()
@@ -248,25 +362,19 @@ struct ImageCarousel<Content: View>: View {
var Medias: some View {
TabView(selection: $model.selectedIndex) {
ForEach(urls.indices, id: \.self) { index in
ForEach(model.urls.indices, id: \.self) { index in
GeometryReader { geo in
Media(geo: geo, url: urls[index], index: index)
Media(geo: geo, url: model.urls[index], index: index)
.onChange(of: geo.size, perform: { new_size in
model.geo_size = new_size
})
.onAppear {
model.geo_size = geo.size
}
}
}
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
.fullScreenCover(isPresented: $model.open_sheet) {
if let content {
FullScreenCarouselView<Content>(video_controller: state.video, urls: urls, settings: state.settings, selectedIndex: $model.selectedIndex) {
content({ // Dismiss closure
model.open_sheet = false
})
}
}
else {
FullScreenCarouselView<AnyView>(video_controller: state.video, urls: urls, settings: state.settings, selectedIndex: $model.selectedIndex)
}
}
.frame(height: height)
.onChange(of: model.selectedIndex) { value in
model.selectedIndex = value
@@ -284,8 +392,8 @@ struct ImageCarousel<Content: View>: View {
}
if urls.count > 1 {
PageControlView(currentPage: $model.selectedIndex, numberOfPages: urls.count)
if model.urls.count > 1 {
PageControlView(currentPage: $model.selectedIndex, numberOfPages: model.urls.count)
.frame(maxWidth: 0, maxHeight: 0)
.padding(.top, 5)
}
@@ -293,27 +401,6 @@ struct ImageCarousel<Content: View>: View {
}
}
// MARK: - Image Modifier
extension KFOptionSetter {
/// Sets a block to get image size
///
/// - Parameter block: The block which is used to read the image object.
/// - Returns: `Self` value after read size
public func imageFill(for size: CGSize, max: CGFloat, fill: CGFloat, block: @escaping (ImageFill) throws -> Void) -> Self {
let modifier = AnyImageModifier { image -> KFCrossPlatformImage in
let img_size = image.size
let geo_size = size
let fill = ImageFill.calculate_image_fill(geo_size: geo_size, img_size: img_size, maxHeight: max, fillHeight: fill)
DispatchQueue.main.async { [block, fill] in
try? block(fill)
}
return image
}
options.imageModifier = modifier
return self
}
}
public struct ImageFill {
let filling: Bool?
@@ -350,4 +437,3 @@ struct ImageCarousel_Previews: PreviewProvider {
.environmentObject(OrientationTracker())
}
}

View File

@@ -84,7 +84,7 @@ struct NoteZapButton: View {
print("cancel_zap: we already have a real zap, can't cancel")
break
case .pending(let pzap):
guard let res = cancel_zap(zap: pzap, box: damus_state.postbox, zapcache: damus_state.zaps, evcache: damus_state.events) else {
guard let res = cancel_zap(zap: pzap, box: damus_state.nostrNetwork.postbox, zapcache: damus_state.zaps, evcache: damus_state.events) else {
UIImpactFeedbackGenerator(style: .soft).impactOccurred()
return
@@ -179,7 +179,7 @@ func send_zap(damus_state: DamusState, target: ZapTarget, lnurl: String, is_cust
}
// Only take the first 10 because reasons
let relays = Array(damus_state.pool.our_descriptors.prefix(10))
let relays = Array(damus_state.nostrNetwork.pool.our_descriptors.prefix(10))
let content = comment ?? ""
guard let mzapreq = make_zap_request_event(keypair: keypair, content: content, relays: relays, target: target, zap_type: zap_type) else {
@@ -232,7 +232,7 @@ func send_zap(damus_state: DamusState, target: ZapTarget, lnurl: String, is_cust
flusher = .once({ pe in
// send donation zap when the pending zap is flushed, this allows user to cancel and not send a donation
Task { @MainActor in
await send_donation_zap(pool: damus_state.pool, postbox: damus_state.postbox, nwc: nwc_state.url, percent: damus_state.settings.donation_percent, base_msats: amount_msat)
await WalletConnect.send_donation_zap(pool: damus_state.nostrNetwork.pool, postbox: damus_state.nostrNetwork.postbox, nwc: nwc_state.url, percent: damus_state.settings.donation_percent, base_msats: amount_msat)
}
})
}
@@ -240,7 +240,7 @@ func send_zap(damus_state: DamusState, target: ZapTarget, lnurl: String, is_cust
// we don't have a delay on one-tap nozaps (since this will be from customize zap view)
let delay = damus_state.settings.nozaps ? nil : 5.0
let nwc_req = nwc_pay(url: nwc_state.url, pool: damus_state.pool, post: damus_state.postbox, invoice: inv, delay: delay, on_flush: flusher)
let nwc_req = WalletConnect.pay(url: nwc_state.url, pool: damus_state.nostrNetwork.pool, post: damus_state.nostrNetwork.postbox, invoice: inv, delay: delay, on_flush: flusher)
guard let nwc_req, case .nwc(let pzap_state) = pending_zap_state else {
print("nwc: failed to send nwc request for zapreq \(reqid.reqid)")

View File

@@ -10,22 +10,68 @@ import SwiftUI
struct Reposted: View {
let damus: DamusState
let pubkey: Pubkey
let target: NostrEvent
@State var reposts: Int
init(damus: DamusState, pubkey: Pubkey, target: NostrEvent) {
self.damus = damus
self.pubkey = pubkey
self.target = target
self.reposts = damus.boosts.counts[target.id] ?? 1
}
var body: some View {
HStack(alignment: .center) {
Image("repost")
.foregroundColor(Color.gray)
ProfileName(pubkey: pubkey, damus: damus, show_nip5_domain: false)
.foregroundColor(Color.gray)
Text("Reposted", comment: "Text indicating that the note was reposted (i.e. re-shared).")
.foregroundColor(Color.gray)
// Show profile picture of the reposter only if the reposter is not the author of the reposted note.
if pubkey != target.pubkey {
ProfilePicView(pubkey: pubkey, size: eventview_pfp_size(.small), highlight: .none, profiles: damus.profiles, disable_animation: damus.settings.disable_animation)
.onTapGesture {
show_profile_action_sheet_if_enabled(damus_state: damus, pubkey: pubkey)
}
.onLongPressGesture(minimumDuration: 0.1) {
UIImpactFeedbackGenerator(style: .medium).impactOccurred()
damus.nav.push(route: Route.ProfileByKey(pubkey: pubkey))
}
}
NavigationLink(value: Route.Reposts(reposts: .reposts(state: damus, target: target.id))) {
Text(people_reposted_text(profiles: damus.profiles, pubkey: pubkey, reposts: reposts))
.font(.subheadline)
.foregroundColor(.gray)
}
}
.onReceive(handle_notify(.update_stats), perform: { note_id in
guard note_id == target.id else { return }
let repost_count = damus.boosts.counts[target.id]
if let repost_count, reposts != repost_count {
reposts = repost_count
}
})
}
}
func people_reposted_text(profiles: Profiles, pubkey: Pubkey, reposts: Int, locale: Locale = Locale.current) -> String {
guard reposts > 0 else {
return ""
}
let bundle = bundleForLocale(locale: locale)
let other_reposts = reposts - 1
let display_name = event_author_name(profiles: profiles, pubkey: pubkey)
if other_reposts == 0 {
return String(format: NSLocalizedString("%@ reposted", bundle: bundle, comment: "Text indicating that the note was reposted (i.e. re-shared)."), locale: locale, display_name)
} else {
return String(format: localizedStringFormat(key: "people_reposted_count", locale: locale), locale: locale, other_reposts, display_name)
}
}
struct Reposted_Previews: PreviewProvider {
static var previews: some View {
let test_state = test_damus_state
Reposted(damus: test_state, pubkey: test_state.pubkey)
Reposted(damus: test_state, pubkey: test_state.pubkey, target: test_note)
}
}

View File

@@ -63,7 +63,7 @@ struct SelectableText: View {
})) {
if let event, case .show_highlight_post_view(let highlighted_text) = self.selectedTextActionState {
PostView(
action: .highlighting(.init(selected_text: highlighted_text, source: .event(event))),
action: .highlighting(.init(selected_text: highlighted_text, source: .event(event.id))),
damus_state: damus_state
)
.presentationDragIndicator(.visible)
@@ -94,12 +94,12 @@ struct SelectableText: View {
case show_mute_word_view(highlighted_text: String)
func should_show_highlight_post_view() -> Bool {
guard case .show_highlight_post_view(let highlighted_text) = self else { return false }
guard case .show_highlight_post_view = self else { return false }
return true
}
func should_show_mute_word_view() -> Bool {
guard case .show_mute_word_view(let highlighted_text) = self else { return false }
guard case .show_mute_word_view = self else { return false }
return true
}
@@ -119,16 +119,23 @@ struct SelectableText: View {
fileprivate class TextView: UITextView {
var postHighlight: (String) -> Void
var muteWord: (String) -> Void
private let enableHighlighting: Bool
init(frame: CGRect, textContainer: NSTextContainer?, postHighlight: @escaping (String) -> Void, muteWord: @escaping (String) -> Void) {
init(frame: CGRect, textContainer: NSTextContainer?, postHighlight: @escaping (String) -> Void, muteWord: @escaping (String) -> Void, enableHighlighting: Bool) {
self.postHighlight = postHighlight
self.muteWord = muteWord
self.enableHighlighting = enableHighlighting
super.init(frame: frame, textContainer: textContainer)
if enableHighlighting {
self.delegate = self
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
fatalError("init(coder:) has not been implemented")
}
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(highlightText(_:)) {
@@ -142,23 +149,44 @@ fileprivate class TextView: UITextView {
return super.canPerformAction(action, withSender: sender)
}
func getSelectedText() -> String? {
private func getSelectedText() -> String? {
guard let selectedRange = self.selectedTextRange else { return nil }
return self.text(in: selectedRange)
}
@objc public func highlightText(_ sender: Any?) {
@objc private func highlightText(_ sender: Any?) {
guard let selectedText = self.getSelectedText() else { return }
self.postHighlight(selectedText)
}
@objc public func muteText(_ sender: Any?) {
@objc private func muteText(_ sender: Any?) {
guard let selectedText = self.getSelectedText() else { return }
self.muteWord(selectedText)
}
}
extension TextView: UITextViewDelegate {
func textView(_ textView: UITextView, editMenuForTextIn range: NSRange, suggestedActions: [UIMenuElement]) -> UIMenu? {
guard enableHighlighting,
let selectedTextRange = self.selectedTextRange,
let selectedText = self.text(in: selectedTextRange),
!selectedText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
return nil
}
let highlightAction = UIAction(title: NSLocalizedString("Highlight", comment: "Context menu action to highlight the selected text as context to draft a new note."), image: UIImage(systemName: "highlighter")) { [weak self] _ in
self?.postHighlight(selectedText)
}
let muteAction = UIAction(title: NSLocalizedString("Mute", comment: "Context menu action to mute the selected word."), image: UIImage(systemName: "speaker.slash")) { [weak self] _ in
self?.muteWord(selectedText)
}
return UIMenu(children: suggestedActions + [highlightAction, muteAction])
}
}
fileprivate struct TextViewRepresentable: UIViewRepresentable {
let attributedString: AttributedString
@@ -172,7 +200,7 @@ fileprivate struct TextViewRepresentable: UIViewRepresentable {
@Binding var height: CGFloat
func makeUIView(context: UIViewRepresentableContext<Self>) -> TextView {
let view = TextView(frame: .zero, textContainer: nil, postHighlight: postHighlight, muteWord: muteWord)
let view = TextView(frame: .zero, textContainer: nil, postHighlight: postHighlight, muteWord: muteWord, enableHighlighting: enableHighlighting)
view.isEditable = false
view.dataDetectorTypes = .all
view.isSelectable = true
@@ -183,11 +211,6 @@ fileprivate struct TextViewRepresentable: UIViewRepresentable {
view.textContainerInset.right = 1.0
view.textAlignment = textAlignment
let menuController = UIMenuController.shared
let highlightItem = UIMenuItem(title: "Highlight", action: #selector(view.highlightText(_:)))
let muteItem = UIMenuItem(title: "Mute", action: #selector(view.muteText(_:)))
menuController.menuItems = self.enableHighlighting ? [highlightItem, muteItem] : []
return view
}

View File

@@ -213,6 +213,6 @@ struct UserStatusSheet: View {
struct UserStatusSheet_Previews: PreviewProvider {
static var previews: some View {
UserStatusSheet(damus_state: test_damus_state, postbox: test_damus_state.postbox, keypair: test_keypair, status: .init())
UserStatusSheet(damus_state: test_damus_state, postbox: test_damus_state.nostrNetwork.postbox, keypair: test_keypair, status: .init())
}
}

View File

@@ -12,6 +12,14 @@ struct SupporterBadge: View {
let purple_account: DamusPurple.Account?
let style: Style
let text_color: Color
var badge_variant: BadgeVariant {
if purple_account?.attributes.contains(.memberForMoreThanOneYear) == true {
return .oneYearSpecial
}
else {
return .normal
}
}
init(percent: Int?, purple_account: DamusPurple.Account? = nil, style: Style, text_color: Color = .secondary) {
self.percent = percent
@@ -26,13 +34,18 @@ struct SupporterBadge: View {
HStack {
if let purple_account, purple_account.active == true {
HStack(spacing: 1) {
Image("star.fill")
.resizable()
.frame(width:size, height:size)
.foregroundStyle(GoldGradient)
if self.style == .full {
let date = format_date(date: purple_account.created_at, time_style: .none)
Text(date)
switch self.badge_variant {
case .normal:
StarShape()
.frame(width:size, height:size)
.foregroundStyle(GoldGradient)
case .oneYearSpecial:
DoubleStar(size: size)
}
if self.style == .full,
let ordinal = self.purple_account?.ordinal() {
Text(ordinal)
.foregroundStyle(text_color)
.font(.caption)
}
@@ -56,8 +69,102 @@ struct SupporterBadge: View {
case full // Shows the entire badge with a purple subscriber number if present
case compact // Does not show purple subscriber number. Only shows the star (if applicable)
}
enum BadgeVariant {
/// A normal badge that people are used to
case normal
/// A special badge for users who have been members for more than a year
case oneYearSpecial
}
}
struct StarShape: Shape {
func path(in rect: CGRect) -> Path {
var path = Path()
let center = CGPoint(x: rect.midX, y: rect.midY)
let radius: CGFloat = min(rect.width, rect.height) / 2
let points = 5
let adjustment: CGFloat = .pi / 2
for i in 0..<points * 2 {
let angle = (CGFloat(i) * .pi / CGFloat(points)) - adjustment
let pointRadius = i % 2 == 0 ? radius : radius * 0.4
let point = CGPoint(x: center.x + pointRadius * cos(angle), y: center.y + pointRadius * sin(angle))
if i == 0 {
path.move(to: point)
} else {
path.addLine(to: point)
}
}
path.closeSubpath()
return path
}
}
struct DoubleStar: View {
let size: CGFloat
var starOffset: CGFloat = 5
var body: some View {
if #available(iOS 17.0, *) {
DoubleStarShape(starOffset: starOffset)
.frame(width: size, height: size)
.foregroundStyle(GoldGradient)
.padding(.trailing, starOffset)
} else {
Fallback(size: size, starOffset: starOffset)
}
}
@available(iOS 17.0, *)
struct DoubleStarShape: Shape {
var strokeSize: CGFloat = 3
var starOffset: CGFloat
func path(in rect: CGRect) -> Path {
let normalSizedStarPath = StarShape().path(in: rect)
let largerStarPath = StarShape().path(in: rect.insetBy(dx: -strokeSize, dy: -strokeSize))
let finalPath = normalSizedStarPath
.subtracting(
largerStarPath.offsetBy(dx: starOffset, dy: 0)
)
.union(
normalSizedStarPath.offsetBy(dx: starOffset, dy: 0)
)
return finalPath
}
}
/// A fallback view for those who cannot run iOS 17
struct Fallback: View {
var size: CGFloat
var starOffset: CGFloat
var body: some View {
HStack {
StarShape()
.frame(width: size, height: size)
.foregroundStyle(GoldGradient)
StarShape()
.fill(GoldGradient)
.overlay(
StarShape()
.stroke(Color.damusAdaptableWhite, lineWidth: 1)
)
.frame(width: size + 1, height: size + 1)
.padding(.leading, -size - starOffset)
}
.padding(.trailing, -3)
}
}
}
func support_level_color(_ percent: Int) -> Color {
if percent == 0 {
return .gray
@@ -86,7 +193,7 @@ struct SupporterBadge_Previews: PreviewProvider {
HStack(alignment: .center) {
SupporterBadge(
percent: nil,
purple_account: DamusPurple.Account(pubkey: test_pubkey, created_at: .now, expiry: .now.addingTimeInterval(10000), subscriber_number: subscriber_number, active: true),
purple_account: DamusPurple.Account(pubkey: test_pubkey, created_at: .now, expiry: .now.addingTimeInterval(10000), subscriber_number: subscriber_number, active: true, attributes: []),
style: .full
)
.frame(width: 100)
@@ -118,4 +225,52 @@ struct SupporterBadge_Previews: PreviewProvider {
}
}
#Preview("1 yr badge") {
VStack {
HStack(alignment: .center) {
SupporterBadge(
percent: nil,
purple_account: DamusPurple.Account(pubkey: test_pubkey, created_at: .now, expiry: .now.addingTimeInterval(10000), subscriber_number: 3, active: true, attributes: []),
style: .full
)
.frame(width: 100)
}
HStack(alignment: .center) {
SupporterBadge(
percent: nil,
purple_account: DamusPurple.Account(pubkey: test_pubkey, created_at: .now, expiry: .now.addingTimeInterval(10000), subscriber_number: 3, active: true, attributes: [.memberForMoreThanOneYear]),
style: .full
)
.frame(width: 100)
}
Text(verbatim: "Double star (just shape itself, with alt background color, to show it adapts to background well)")
.multilineTextAlignment(.center)
if #available(iOS 17.0, *) {
HStack(alignment: .center) {
DoubleStar.DoubleStarShape(starOffset: 5)
.frame(width: 17, height: 17)
.padding(.trailing, -8)
}
.background(Color.blue)
}
Text(verbatim: "Double star (fallback for iOS 16 and below)")
HStack(alignment: .center) {
DoubleStar.Fallback(size: 17, starOffset: 5)
}
Text(verbatim: "Double star (fallback for iOS 16 and below, with alt color limitation shown)")
.multilineTextAlignment(.center)
HStack(alignment: .center) {
DoubleStar.Fallback(size: 17, starOffset: 5)
}
.background(Color.blue)
}
}

View File

@@ -27,19 +27,26 @@ struct TranslateView: View {
let damus_state: DamusState
let event: NostrEvent
let size: EventViewKind
@Binding var isAppleTranslationPopoverPresented: Bool
@ObservedObject var translations_model: TranslationModel
init(damus_state: DamusState, event: NostrEvent, size: EventViewKind) {
init(damus_state: DamusState, event: NostrEvent, size: EventViewKind, isAppleTranslationPopoverPresented: Binding<Bool>) {
self.damus_state = damus_state
self.event = event
self.size = size
self._isAppleTranslationPopoverPresented = isAppleTranslationPopoverPresented
self._translations_model = ObservedObject(wrappedValue: damus_state.events.get_cache_data(event.id).translations_model)
}
var TranslateButton: some View {
Button(NSLocalizedString("Translate Note", comment: "Button to translate note from different language.")) {
translate()
if damus_state.settings.translation_service == .none {
isAppleTranslationPopoverPresented = true
} else {
translate()
}
}
.translate_button_style()
}
@@ -74,17 +81,25 @@ struct TranslateView: View {
}
func should_transl(_ note_lang: String) -> Bool {
should_translate(event: event, our_keypair: damus_state.keypair, settings: damus_state.settings, note_lang: note_lang)
guard should_translate(event: event, our_keypair: damus_state.keypair, note_lang: note_lang) else {
return false
}
if TranslationService.isAppleTranslationPopoverSupported {
return damus_state.settings.translation_service == .none || damus_state.settings.can_translate
} else {
return damus_state.settings.can_translate
}
}
var body: some View {
Group {
switch self.translations_model.state {
case .havent_tried:
if damus_state.settings.auto_translate {
if damus_state.settings.auto_translate && damus_state.settings.translation_service != .none {
Text("")
} else if let note_lang = translations_model.note_language, should_transl(note_lang) {
TranslateButton
TranslateButton
} else {
Text("")
}
@@ -114,9 +129,11 @@ extension View {
}
struct TranslateView_Previews: PreviewProvider {
@State static var isAppleTranslationPopoverPresented: Bool = false
static var previews: some View {
let ds = test_damus_state
TranslateView(damus_state: ds, event: test_note, size: .normal)
TranslateView(damus_state: ds, event: test_note, size: .normal, isAppleTranslationPopoverPresented: $isAppleTranslationPopoverPresented)
}
}
@@ -143,7 +160,7 @@ func translate_note(profiles: Profiles, keypair: Keypair, event: NostrEvent, set
// Render translated note
let translated_blocks = parse_note_content(content: .content(translated_note, event.tags))
let artifacts = render_blocks(blocks: translated_blocks, profiles: profiles)
let artifacts = render_blocks(blocks: translated_blocks, profiles: profiles, can_hide_last_previewable_refs: true)
// and cache it
return .translated(Translated(artifacts: artifacts, language: note_lang))

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