Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
54c8a5b2ce
|
|||
| 00c819140b | |||
| cbc3c46c9d | |||
| 4b5c34b4e2 | |||
| 9eb39f7e0a | |||
| 173b22b772 | |||
| 18c7cba53c | |||
| 9a40fd595d | |||
| a71c35a6b0 | |||
| d69d3cc74e | |||
| 6e220ac4c1 | |||
| bcb40a6ec7 | |||
| 2f1063b49f | |||
| 73110952e5 | |||
| d01e7c0595 | |||
| 4f9cef541b | |||
| 2dfbc4b57e | |||
| b9750dab77 | |||
| d59331bc3c | |||
| abd5856f21 | |||
| 42a475bd72 | |||
| 65c1325935 | |||
| db64a73f87 | |||
| 9d44ed0bfe | |||
| 33383265c8 | |||
| 76d1ee34d8 | |||
| 3b0a84bd43 | |||
| 5a1daebeca | |||
| 08666ff90d | |||
| b2b790a969 | |||
| 907f0d236f | |||
| 4b8f536a9b | |||
| c76f92c6ed | |||
| a165f4281c | |||
| 5dbf8029da | |||
| b1885700ca |
@@ -0,0 +1,27 @@
|
||||
name: Export localizations
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
pull_request:
|
||||
branches:
|
||||
- "*"
|
||||
jobs:
|
||||
export_localizations:
|
||||
name: Export localizations
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Export Localizations
|
||||
run: xcodebuild -exportLocalizations -project damus.xcodeproj -localizationPath "damus Localizations" -exportLanguage en-US -exportLanguage es-419
|
||||
- name: Verify Source Localization
|
||||
run:
|
||||
- name: Commit Localizations
|
||||
run: |
|
||||
git --version
|
||||
git config user.name "GitHub Actions Bot"
|
||||
git config user.email "<>"
|
||||
git status
|
||||
git add damus/*.lproj "damus Localizations"
|
||||
git commit -m ""
|
||||
@@ -0,0 +1,26 @@
|
||||
name: Import localizations on Transifex pull requests
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'transifex/**'
|
||||
paths:
|
||||
- 'damus Localizations/*.xcloc/Localized Contents/*.xliff'
|
||||
- '!damus Localizations/en-US.xcloc/Localized Contents/en-US.xliff'
|
||||
jobs:
|
||||
import_localizations:
|
||||
name: Import localizations on Transifex pull requests
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
- name: Import localizations
|
||||
run: find "damus Localizations" -name "*.xliff" | grep -v "en-US.xliff" | xargs -I % xcodebuild -importLocalizations -project damus.xcodeproj -localizationPath %
|
||||
- name: Commit imported localizations
|
||||
uses: EndBug/add-and-commit@v9
|
||||
with:
|
||||
default_author: github_actions
|
||||
add: '"**.strings" "**.stringsdict"'
|
||||
message: 'Import localizations'
|
||||
@@ -1,33 +0,0 @@
|
||||
name: Nostr PR Notifier
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, reopened]
|
||||
jobs:
|
||||
Notify:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
# Set in Github repo > Settings > Secrets and Variables
|
||||
NOSTR_KEY: ${{ secrets.NOSTR_KEY }}
|
||||
# Event vars
|
||||
PR_URL: ${{ github.event.pull_request.html_url }}
|
||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
|
||||
PR_BODY: ${{ github.event.pull_request.body }}
|
||||
steps:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.19.0'
|
||||
- run: go install github.com/fiatjaf/noscl@latest
|
||||
- run: which noscl
|
||||
- run: noscl setprivate $NOSTR_KEY
|
||||
- run: noscl relay add wss://relay.damus.io
|
||||
- run: noscl relay add wss://brb.io
|
||||
- run: noscl relay add wss://relay.nostr.info
|
||||
- run: noscl relay add wss://nostr.zebedee.cloud
|
||||
- run: noscl relay add wss://nostr.orangepill.dev
|
||||
- run: noscl relay add wss://nostr.v0l.io
|
||||
- run: noscl relay add wss://nostr.fmt.wiz.biz
|
||||
- run: |
|
||||
msg=$(printf "Pull request opened by $PR_AUTHOR\n$PR_TITLE\n$PR_URL") \
|
||||
&& noscl publish "$msg"
|
||||
@@ -0,0 +1,17 @@
|
||||
name: Test
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
pull_request:
|
||||
branches:
|
||||
- "*"
|
||||
jobs:
|
||||
test:
|
||||
name: Run Tests
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v1
|
||||
- name: Running Tests
|
||||
run: xcodebuild test -scheme damus -project damus.xcodeproj -destination 'platform=iOS Simulator,name=iPhone 14,OS=16.0' | xcpretty && exit ${PIPESTATUS[0]}
|
||||
@@ -1,3 +1,35 @@
|
||||
## [1.0.0-6] - 2023-01-13
|
||||
|
||||
### Added
|
||||
|
||||
- Profile banner images (Jason Jōb)
|
||||
- Added Reactions View (William Casarin)
|
||||
- Left hand option for post button (Jonathan Milligan)
|
||||
- Damus icon at the top (Ben Weeks)
|
||||
- Make purple badges on profile page tappable (Joel Klabo)
|
||||
|
||||
|
||||
### Changed
|
||||
|
||||
- Make Shaka button purple when liked (Joel Klabo)
|
||||
- Move counts to right side like Birdsite (Joel Klabo)
|
||||
- Use custom icon for shaka button (Joel Klabo)
|
||||
- Renamed boost to repost (William Casarin)
|
||||
- Removed nip05 domain from boosts/reposts (William Casarin)
|
||||
- Make DMs only take up 80% of screen width (Jonathan Milligan)
|
||||
- Hide Recommended Relays Section if Empty (Joel Klabo)
|
||||
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed shaka moving when you press it (Joel Klabo)
|
||||
- Fixed issue with relays not keeping in sync when adding (Fredrik Olofsson)
|
||||
|
||||
|
||||
|
||||
[1.0.0-6]: https://github.com/damus-io/damus/releases/tag/v1.0.0-6
|
||||
|
||||
|
||||
## [1.0.0-5] - 2023-01-06
|
||||
|
||||
### Added
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
# damus
|
||||
|
||||
A twitter-like [nostr][nostr] client for iPhone, iPad and MacOS.
|
||||
A Twitter-like [nostr][nostr] client for iPhone, iPad, and Mac.
|
||||
|
||||
<img src="./ss.png" width="50%" height="50%" />
|
||||
|
||||
@@ -25,42 +25,42 @@ damus implements the following [Nostr Implementation Possibilities][nips]
|
||||
## Getting Started on Damus
|
||||
|
||||
### Damus iOS
|
||||
1) Get the Damus app on Testflight: https://testflight.apple.com/join/CLwjLxWl
|
||||
1) Get the Damus app on TestFlight: https://testflight.apple.com/join/CLwjLxWl
|
||||
|
||||
#### ⚙️ Settings (gear icon, top right)
|
||||
- Relays: You can add more relays to send your notes to by tapping the "+".
|
||||
- Relays: You can add more relays to send your notes by tapping the "+"
|
||||
- Find more relays to add: https://nostr.info/relays/
|
||||
- Public Key (pubkey): Your public, personal address and how people can find and tag you
|
||||
- Secret Key: Your *private* key unique to you. Never share your private key publically and share with other clients at your own risk!
|
||||
- Secret Key: Your *private* key, unique to you. Never share your private key publically, and share with other clients at your own risk!
|
||||
- Save your keys somewhere safe
|
||||
- Log out
|
||||
|
||||
#### 🏠 Personal Feed (home icon, bottom navigation)
|
||||
- Feed from everyone you follow
|
||||
- Can post notes by tapping the blue + button
|
||||
- Can post notes by tapping the blue "+" button
|
||||
|
||||
#### Notes (under 🏠 Personal Feed)
|
||||
- Sending a Note is easy and it goes to both your 🏠 Personal and 🔍 Global Feeds
|
||||
- To tag a user you must grab their pubkey:
|
||||
- Sending a Note is easy, and it goes to both your 🏠 Personal and 🔍 Global Feeds
|
||||
- To tag a user, you must grab their pubkey:
|
||||
1. Search their username in the search bar at the top of the 🔍 Global Feed and click their profile
|
||||
2. Tap the 🔑 icon which will copy their pubkey to your clipboard
|
||||
3. Go back to your 🏠 Personal Feed and tap the blue + button to compose your Note
|
||||
4. Add @ direcly followed by the pubkey (e.g., `@npub1xtscya34g58tk0z605fvr788k263gsu6cy9x0mhnm87echrgufzsevkk5s`)
|
||||
- You can also long-press a Note to grab their User ID aka pubkey or Note ID to link directly to a Note.
|
||||
- Currently you can't delete your Notes in the iOS app
|
||||
- Share images by pasting the image url which you can grab from imgbb, imgur, etc. (i.e., `(https://i.ibb.co/2SHZbwm/alpha60.jpg)`). Currently images only load for people you follow in the 🏠 Personal Feed. Images are not automatically loaded in 🔍 Global Feed
|
||||
2. Tap the 🔑 icon, which will copy their pubkey to your clipboard
|
||||
3. Go back to your 🏠 Personal Feed and tap the blue "+" button to compose your Note
|
||||
4. Add @ directly followed by the pubkey (e.g., `@npub1xtscya34g58tk0z605fvr788k263gsu6cy9x0mhnm87echrgufzsevkk5s`)
|
||||
- You can also long-press a Note to grab their User ID (pubkey) or Note ID to link directly to a Note.
|
||||
- Currently, you can't delete your Notes in the iOS app
|
||||
- Share images by pasting the image URL, which you can grab from nostr.build, imgbb, imgur, etc. (e.g., `(https://i.ibb.co/2SHZbwm/alpha60.jpg)`). Currently, images only load for people you follow in the 🏠 Personal Feed. Images are not automatically loaded in 🔍 Global Feed
|
||||
- Engaging with Notes
|
||||
- 💬 Replying to a Note: Tap the chat icon underneath the note. This will show up in the users’ notifications and in your 🏠 Personal and 🔍 Global Feeds
|
||||
- ♺ Reposts: Tap the repost icon which will show up in your 🏠 Personal and 🔍 Global Feeds
|
||||
- ♡ Likes: Tap the heart icon. Users will not get a notification, and cannot see who liked their note (currently, web clients can see your pfp only)
|
||||
- 💬 Replying to a Note: Tap the chat icon underneath the note. This icon will show up in the users' notifications and in your 🏠 Personal and 🔍 Global Feeds
|
||||
- 🔁 Reposts: Tap the repost icon, which will show up in your 🏠 Personal and 🔍 Global Feeds
|
||||
- 🤙 Reactions: Tap the shaka icon. Users will not get a notification, but they can see who reacted to their note
|
||||
- Formatting Notes (may not format as intended in other web clients)
|
||||
- Italics: 1 asterisk `*italic*`
|
||||
- Bold: 2 asterisk `**bold**`
|
||||
- Bold: 2 asterisks `**bold**`
|
||||
- Strikethrough: 1 tildes `~strikethrough~`
|
||||
- Code: 1 back-tick `` `code` ``
|
||||
|
||||
#### 💬 Encrypted DMs (chat app, bottom navigation)
|
||||
- Tap the chat icon and you'll notice there's nothing to see at first. Go to a user profile and tap the 💬 chat icon next to the follow button to begin a DM
|
||||
- Tap the chat icon and you'll notice nothing to see at first. Go to a user profile and tap the 💬 chat icon next to the follow button to begin a DM
|
||||
|
||||
#### 🔍 Global Feed (magnify glass, bottom navigation)
|
||||
- View the Global Feed from all the relays you've added in ⚙️ Settings. Currently you can only search hashtags and user names and pubkeys
|
||||
@@ -80,21 +80,30 @@ damus implements the following [Nostr Implementation Possibilities][nips]
|
||||
|
||||
**Alby (browser extension)**
|
||||
- Get the [Alby](https://getalby.com/) browser extension and create your Alby address [yourname]@getalby.com or connect your existing Lightning wallet
|
||||
- Convert your Damus secret key from nsec to hex at https://damus.io/key then go to Settings in Alby and under the Nostr section at the bottom of the page add your private hex key. You can also generate new address in the extension
|
||||
- Click the Alby extension > click Receive > enter the amount of Sats > click Get Invoice > click Copy > then paste into Damus
|
||||
- Convert your Damus secret key from nsec to hex at https://damus.io/key then go to "Settings" in Alby and under the "Nostr" section at the bottom of the page add your private hex key. You can also generate new address in the extension
|
||||
- Click the Alby extension > click "Receive" > enter the amount of Sats > click "Get Invoice" > click "Copy" > then paste into Damus
|
||||
- Note: On Damus Web it will appear as a string of characters but on Damus iOS it will appear as a clickable image
|
||||
|
||||
**Zeus (mobile app)**
|
||||
- Download [Zeus](https://zeusln.app/) app (iOS, Google, APK)
|
||||
- Tap Get Started button > tap Connect a node > click on + sign (top right) > select Indhub > press Scan Lndhub QR > (from the Alby browser extension… click your account on the top left > click Manage Accounts > click 3-dot menu to right of your account and click Export Account to get a QR code then go back to Zeus app) > scan the QR Code and tap Save Node Config button
|
||||
- To create an invoice tap Lightning > tap Receive > type in amount > tap Create Invoice > tap Copy Invoice > paste into a new Damus note
|
||||
- Tap "Get Started" button > tap "Connect a node" > click on "+" sign (top right) > select "Indhub" > press "Scan Lndhub QR" > (from the Alby browser extension… click your account on the top left > click "Manage Accounts" > click 3-dot menu to the right of your account and click "Export Account" to get a QR code then go back to Zeus app) > scan the QR Code and tap "Save Node Config" button
|
||||
- To create an invoice, tap "Lightning" > tap "Receive" > type in amount > tap "Create Invoice" > tap "Copy Invoice" > paste into a new Damus note
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributors welcome! [Email patches][git-send-email] to jb55@jb55.com are preferred, but I accept PRs on github as well.
|
||||
### Code
|
||||
|
||||
Contributors welcome! [Email patches][git-send-email] to jb55@jb55.com are preferred, but I accept PRs on GitHub as well.
|
||||
|
||||
[git-send-email]: http://git-send-email.io
|
||||
|
||||
### Translations
|
||||
|
||||
Translators welcome! Join the [Transifex][transifex] project. If you do not see your language, add it to the [Xcode project][xcode-add-language] and [export_localizations.yaml](.github/workflows/export_localizations.yaml), or reach out to .
|
||||
|
||||
[transifex]: https://explore.transifex.com/damus/damus-ios/
|
||||
[xcode-add-language]: https://developer.apple.com/documentation/xcode/adding-support-for-languages-and-regions
|
||||
|
||||
## git log bot
|
||||
|
||||
npub1fjtdwclt9lspjy8huu3qklr7eklp5uq90u6yh8mec290pqxraccqlufnas
|
||||
@@ -105,5 +114,5 @@ There may be nostr badges awarded for contributors in the future... :)
|
||||
|
||||
First contributors:
|
||||
|
||||
1. @randymcmillan
|
||||
2. @jcarucci27
|
||||
1. [@randymcmillan](https://github.com/randymcmillan)
|
||||
2. [@jcarucci27](https://github.com/jcarucci27)
|
||||
|
||||
@@ -35,12 +35,14 @@
|
||||
<trans-unit id="%@" xml:space="preserve">
|
||||
<source>%@</source>
|
||||
<target>%@</target>
|
||||
<note>Number of people following a user.</note>
|
||||
<note>Amount of time that has passed since reply quote event occurred.
|
||||
Abbreviated version of a nostr public key.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ %@" xml:space="preserve">
|
||||
<source>%@ %@</source>
|
||||
<target>%@ %@</target>
|
||||
<note>Sentence composed of 2 variables to describe how many profiles a user is following. In source English, the first variable is the number of profiles being followed, and the second variable is 'Following'.</note>
|
||||
<note>Sentence composed of 2 variables to describe how many reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.
|
||||
Sentence composed of 2 variables to describe how many profiles a user is following. In source English, the first variable is the number of profiles being followed, and the second variable is 'Following'.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@. Creating an account doesn't require a phone number, email or name. Get started right away with zero friction." xml:space="preserve">
|
||||
<source>%@. Creating an account doesn't require a phone number, email or name. Get started right away with zero friction.</source>
|
||||
@@ -60,18 +62,14 @@
|
||||
<trans-unit id="%lld" xml:space="preserve">
|
||||
<source>%lld</source>
|
||||
<target>%lld</target>
|
||||
<note>Number of profiles a user is following.</note>
|
||||
<note>Number of reposts.
|
||||
Number of profiles a user is following.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%lld/%lld" xml:space="preserve">
|
||||
<source>%lld/%lld</source>
|
||||
<target>%lld/%lld</target>
|
||||
<note>Fraction of how many of the user's relay servers that are operational.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="&nbsp;" xml:space="preserve">
|
||||
<source>&nbsp;</source>
|
||||
<target>&nbsp;</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="'%@' at '%@' will be used for verification" xml:space="preserve">
|
||||
<source>'%@' at '%@' will be used for verification</source>
|
||||
<target>'%@' at '%@' will be used for verification</target>
|
||||
@@ -87,16 +85,6 @@
|
||||
<target>(Profile.displayName(profile: profile, pubkey: whos))'s Followers</target>
|
||||
<note>Navigation bar title for view that shows who is following a user.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="(formattedSats) sat" xml:space="preserve">
|
||||
<source>(formattedSats) sat</source>
|
||||
<target>(formattedSats) sat</target>
|
||||
<note>Amount of 1 sat.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="(formattedSats) sats" xml:space="preserve">
|
||||
<source>(formattedSats) sats</source>
|
||||
<target>(formattedSats) sats</target>
|
||||
<note>Amount of sats.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="(who) following" xml:space="preserve">
|
||||
<source>(who) following</source>
|
||||
<target>(who) following</target>
|
||||
@@ -148,10 +136,15 @@
|
||||
<target>Any</target>
|
||||
<note>Any amount of sats</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Are you sure you want to boost this post?" xml:space="preserve">
|
||||
<source>Are you sure you want to boost this post?</source>
|
||||
<target>Are you sure you want to boost this post?</target>
|
||||
<note>Alert message to ask if user wants to boost a post.</note>
|
||||
<trans-unit id="Are you sure you want to repost this?" xml:space="preserve">
|
||||
<source>Are you sure you want to repost this?</source>
|
||||
<target>Are you sure you want to repost this?</target>
|
||||
<note>Alert message to ask if user wants to repost a post.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Banner Image" xml:space="preserve">
|
||||
<source>Banner Image</source>
|
||||
<target>Banner Image</target>
|
||||
<note>Label for Banner Image section of user profile form.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Before we get started, you'll need to save your account info, otherwise you won't be able to login in the future if you ever uninstall Damus." xml:space="preserve">
|
||||
<source>Before we get started, you'll need to save your account info, otherwise you won't be able to login in the future if you ever uninstall Damus.</source>
|
||||
@@ -178,17 +171,6 @@
|
||||
<target>Blue Wallet</target>
|
||||
<note>Dropdown option label for Lightning wallet, Blue Wallet.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Boost" xml:space="preserve">
|
||||
<source>Boost</source>
|
||||
<target>Boost</target>
|
||||
<note>Button to confirm boosting a post.
|
||||
Title of alert for confirming to boost a post.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Boosted" xml:space="preserve">
|
||||
<source>Boosted</source>
|
||||
<target>Boosted</target>
|
||||
<note>Text indicating that the post was boosted (i.e. re-shared).</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Breez" xml:space="preserve">
|
||||
<source>Breez</source>
|
||||
<target>Breez</target>
|
||||
@@ -203,6 +185,7 @@
|
||||
<source>Cancel</source>
|
||||
<target>Cancel</target>
|
||||
<note>Button to cancel out of posting a note.
|
||||
Button to cancel out of reposting a post.
|
||||
Button to cancel out of view adding user inputted relay.
|
||||
Cancel out of logging out the user.</note>
|
||||
</trans-unit>
|
||||
@@ -342,11 +325,6 @@
|
||||
<target>Edit</target>
|
||||
<note>Button to edit user's profile.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Edit Profile" xml:space="preserve">
|
||||
<source>Edit Profile</source>
|
||||
<target>Edit Profile</target>
|
||||
<note>Title of navigation view for Edit Profile.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypted" xml:space="preserve">
|
||||
<source>Encrypted</source>
|
||||
<target>Encrypted</target>
|
||||
@@ -428,6 +406,11 @@ Part of a larger sentence to describe how many profiles a user is following.</no
|
||||
<target>LNLink</target>
|
||||
<note>Dropdown option label for Lightning wallet, LNLink.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Left Handed" xml:space="preserve">
|
||||
<source>Left Handed</source>
|
||||
<target>Left Handed</target>
|
||||
<note>Moves the post button to the left side of the screen</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Let's go!" xml:space="preserve">
|
||||
<source>Let's go!</source>
|
||||
<target>Let's go!</target>
|
||||
@@ -451,7 +434,8 @@ Part of a larger sentence to describe how many profiles a user is following.</no
|
||||
<trans-unit id="Login" xml:space="preserve">
|
||||
<source>Login</source>
|
||||
<target>Login</target>
|
||||
<note>Button to log into account.</note>
|
||||
<note>Button to log into account.
|
||||
Button to log into an account.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Logout" xml:space="preserve">
|
||||
<source>Logout</source>
|
||||
@@ -530,6 +514,11 @@ Part of a larger sentence to describe how many profiles a user is following.</no
|
||||
<target>PrivateKey</target>
|
||||
<note>Title of the secure field that holds the user's private key.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Profile" xml:space="preserve">
|
||||
<source>Profile</source>
|
||||
<target>Profile</target>
|
||||
<note>Sidebar menu label for Profile view.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Profile Picture" xml:space="preserve">
|
||||
<source>Profile Picture</source>
|
||||
<target>Profile Picture</target>
|
||||
@@ -555,6 +544,11 @@ Part of a larger sentence to describe how many profiles a user is following.</no
|
||||
<target>Public key</target>
|
||||
<note>Label indicating that the text is a user's public account key.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Reactions" xml:space="preserve">
|
||||
<source>Reactions</source>
|
||||
<target>Reactions</target>
|
||||
<note>Navigation bar title for Reactions view.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Recommended Relays" xml:space="preserve">
|
||||
<source>Recommended Relays</source>
|
||||
<target>Recommended Relays</target>
|
||||
@@ -568,8 +562,7 @@ Part of a larger sentence to describe how many profiles a user is following.</no
|
||||
<trans-unit id="Relays" xml:space="preserve">
|
||||
<source>Relays</source>
|
||||
<target>Relays</target>
|
||||
<note>Header text for relay server list for configuration.
|
||||
Part of a larger sentence to describe how many relay servers a user is connected.</note>
|
||||
<note>Sidebar menu label for Relay servers view</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Reply to self" xml:space="preserve">
|
||||
<source>Reply to self</source>
|
||||
@@ -586,11 +579,27 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
<target>Replying to:</target>
|
||||
<note>Indicating that the user is replying to the following listed people.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repost" xml:space="preserve">
|
||||
<source>Repost</source>
|
||||
<target>Repost</target>
|
||||
<note>Button to confirm reposting a post.
|
||||
Title of alert for confirming to repost a post.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Reposted" xml:space="preserve">
|
||||
<source>Reposted</source>
|
||||
<target>Reposted</target>
|
||||
<note>Text indicating that the post was reposted (i.e. re-shared).</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Reset" xml:space="preserve">
|
||||
<source>Reset</source>
|
||||
<target>Reset</target>
|
||||
<note>Section title for resetting the user</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Retry" xml:space="preserve">
|
||||
<source>Retry</source>
|
||||
<target>Retry</target>
|
||||
<note>Button to retry completing account creation after an error occurred.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="River" xml:space="preserve">
|
||||
<source>River</source>
|
||||
<target>River</target>
|
||||
@@ -644,7 +653,8 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
<trans-unit id="Settings" xml:space="preserve">
|
||||
<source>Settings</source>
|
||||
<target>Settings</target>
|
||||
<note>Navigation title for Settings view.</note>
|
||||
<note>Navigation title for Settings view.
|
||||
Sidebar menu label for accessing the app settings</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Share" xml:space="preserve">
|
||||
<source>Share</source>
|
||||
@@ -661,6 +671,11 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
<target>Show wallet selector</target>
|
||||
<note>Toggle to show or hide selection of wallet.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Sign out" xml:space="preserve">
|
||||
<source>Sign out</source>
|
||||
<target>Sign out</target>
|
||||
<note>Sidebar menu label to sign out of the account.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Strike" xml:space="preserve">
|
||||
<source>Strike</source>
|
||||
<target>Strike</target>
|
||||
@@ -723,6 +738,11 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
<note>Label for Username section of user profile form.
|
||||
Label to prompt username entry.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Wallet" xml:space="preserve">
|
||||
<source>Wallet</source>
|
||||
<target>Wallet</target>
|
||||
<note>Sidebar menu label for Wallet view.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Wallet Of Satoshi" xml:space="preserve">
|
||||
<source>Wallet Of Satoshi</source>
|
||||
<target>Wallet Of Satoshi</target>
|
||||
@@ -768,6 +788,11 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
<target>collapsed_event_view_other_notes</target>
|
||||
<note>Text to indicate that the thread was collapsed and that there are other notes to view if tapped. (Key in .stringsdict)</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="followers_count" translate="no" xml:space="preserve">
|
||||
<source>followers_count</source>
|
||||
<target>followers_count</target>
|
||||
<note>Part of a larger sentence to describe how many people are following a user. (Key in .stringsdict)</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="https://example.com/pic.jpg" xml:space="preserve">
|
||||
<source>https://example.com/pic.jpg</source>
|
||||
<target>https://example.com/pic.jpg</target>
|
||||
@@ -803,6 +828,16 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
<target>optional</target>
|
||||
<note>Label indicating that a form input is optional.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="reactions_count" translate="no" xml:space="preserve">
|
||||
<source>reactions_count</source>
|
||||
<target>reactions_count</target>
|
||||
<note>Part of a larger sentence to describe how many reactions there are on a post. (Key in .stringsdict)</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="relays_count" translate="no" xml:space="preserve">
|
||||
<source>relays_count</source>
|
||||
<target>relays_count</target>
|
||||
<note>Part of a larger sentence to describe how many relay servers a user is connected. (Key in .stringsdict)</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="replying_to_one_and_others" translate="no" xml:space="preserve">
|
||||
<source>replying_to_one_and_others</source>
|
||||
<target>replying_to_one_and_others</target>
|
||||
@@ -813,11 +848,31 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
<target>replying_to_two_and_others</target>
|
||||
<note>Label to indicate that the user is replying to 2 users and others. (Key in .stringsdict)</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="reposts_count" translate="no" xml:space="preserve">
|
||||
<source>reposts_count</source>
|
||||
<target>reposts_count</target>
|
||||
<note>Part of a larger sentence to describe how many reposts there are. (Key in .stringsdict)</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="satoshi" xml:space="preserve">
|
||||
<source>satoshi</source>
|
||||
<target>satoshi</target>
|
||||
<note>Example username of Bitcoin creator(s), Satoshi Nakamoto.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="sats_count" translate="no" xml:space="preserve">
|
||||
<source>sats_count</source>
|
||||
<target>sats_count</target>
|
||||
<note>Amount of sats. (Key in .stringsdict)</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="tips_count" translate="no" xml:space="preserve">
|
||||
<source>tips_count</source>
|
||||
<target>tips_count</target>
|
||||
<note>Part of a larger sentence to describe how many tip payments there are on a post. (Key in .stringsdict)</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="u{00A0}" xml:space="preserve">
|
||||
<source>u{00A0}</source>
|
||||
<target>u{00A0}</target>
|
||||
<note>Non-breaking space character to fill in blank space next to event action button icons.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="wss://some.relay.com" xml:space="preserve">
|
||||
<source>wss://some.relay.com</source>
|
||||
<target>wss://some.relay.com</target>
|
||||
@@ -828,11 +883,6 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
<target>you</target>
|
||||
<note>You, in this context, is the person who controls their own social network. You is used in the context of a larger sentence that welcomes the reader to the social network that they control themself.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="🤙" xml:space="preserve">
|
||||
<source>🤙</source>
|
||||
<target>🤙</target>
|
||||
<note>Button with emoji to like an event.</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="damus/en-US.lproj/Localizable.stringsdict" source-language="en-US" target-language="en-US" datatype="plaintext">
|
||||
@@ -841,8 +891,8 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
</header>
|
||||
<body>
|
||||
<trans-unit id="/collapsed_event_view_other_notes:dict/NOTES:dict/one:dict/:string" xml:space="preserve">
|
||||
<source>1 other note</source>
|
||||
<target>1 other note</target>
|
||||
<source>%d other note</source>
|
||||
<target>%d other note</target>
|
||||
<note>Text to indicate that the thread was collapsed and that there are other notes to view if tapped.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/collapsed_event_view_other_notes:dict/NOTES:dict/other:dict/:string" xml:space="preserve">
|
||||
@@ -850,24 +900,64 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
<target>%d other notes</target>
|
||||
<note>Text to indicate that the thread was collapsed and that there are other notes to view if tapped.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/collapsed_event_view_other_notes:dict/NOTES:dict/zero:dict/:string" xml:space="preserve">
|
||||
<source>0 other notes</source>
|
||||
<target>0 other notes</target>
|
||||
<note>Text to indicate that the thread was collapsed and that there are other notes to view if tapped.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/collapsed_event_view_other_notes:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
|
||||
<source>··· %#@NOTES@ ···</source>
|
||||
<target>··· %#@NOTES@ ···</target>
|
||||
<note>Text to indicate that the thread was collapsed and that there are other notes to view if tapped.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/followers_count:dict/FOLLOWERS:dict/one:dict/:string" xml:space="preserve">
|
||||
<source>Follower</source>
|
||||
<target>Follower</target>
|
||||
<note>Part of a larger sentence to describe how many people are following a user.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/followers_count:dict/FOLLOWERS:dict/other:dict/:string" xml:space="preserve">
|
||||
<source>Followers</source>
|
||||
<target>Followers</target>
|
||||
<note>Part of a larger sentence to describe how many people are following a user.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/followers_count:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
|
||||
<source>%#@FOLLOWERS@</source>
|
||||
<target>%#@FOLLOWERS@</target>
|
||||
<note>Part of a larger sentence to describe how many people are following a user.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/reactions_count:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
|
||||
<source>%#@REACTIONS@</source>
|
||||
<target>%#@REACTIONS@</target>
|
||||
<note>Part of a larger sentence to describe how many reactions there are on a post.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/reactions_count:dict/REACTIONS:dict/one:dict/:string" xml:space="preserve">
|
||||
<source>Reaction</source>
|
||||
<target>Reaction</target>
|
||||
<note>Part of a larger sentence to describe how many reactions there are on a post.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/reactions_count:dict/REACTIONS:dict/other:dict/:string" xml:space="preserve">
|
||||
<source>Reactions</source>
|
||||
<target>Reactions</target>
|
||||
<note>Part of a larger sentence to describe how many reactions there are on a post.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/relays_count:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
|
||||
<source>%#@RELAYS@</source>
|
||||
<target>%#@RELAYS@</target>
|
||||
<note>Part of a larger sentence to describe how many relay servers a user is connected.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/relays_count:dict/RELAYS:dict/one:dict/:string" xml:space="preserve">
|
||||
<source>Relay</source>
|
||||
<target>Relay</target>
|
||||
<note>Part of a larger sentence to describe how many relay servers a user is connected.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/relays_count:dict/RELAYS:dict/other:dict/:string" xml:space="preserve">
|
||||
<source>Relays</source>
|
||||
<target>Relays</target>
|
||||
<note>Part of a larger sentence to describe how many relay servers a user is connected.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/replying_to_one_and_others:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
|
||||
<source>Replying to %@%#@OTHERS@</source>
|
||||
<target>Replying to %@%#@OTHERS@</target>
|
||||
<note>Label to indicate that the user is replying to 1 user and others.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/replying_to_one_and_others:dict/OTHERS:dict/one:dict/:string" xml:space="preserve">
|
||||
<source> & 1 other</source>
|
||||
<target> & 1 other</target>
|
||||
<source> & %d other</source>
|
||||
<target> & %d other</target>
|
||||
<note>Label to indicate that the user is replying to 1 user and others.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/replying_to_one_and_others:dict/OTHERS:dict/other:dict/:string" xml:space="preserve">
|
||||
@@ -886,8 +976,8 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
<note>Label to indicate that the user is replying to 2 users and others.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/replying_to_two_and_others:dict/OTHERS:dict/one:dict/:string" xml:space="preserve">
|
||||
<source> & 1 other</source>
|
||||
<target> & 1 other</target>
|
||||
<source> & %d other</source>
|
||||
<target> & %d other</target>
|
||||
<note>Label to indicate that the user is replying to 2 users and others.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/replying_to_two_and_others:dict/OTHERS:dict/other:dict/:string" xml:space="preserve">
|
||||
@@ -900,6 +990,51 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
<target/>
|
||||
<note>Label to indicate that the user is replying to 2 users and others.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/reposts_count:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
|
||||
<source>%#@REPOSTS@</source>
|
||||
<target>%#@REPOSTS@</target>
|
||||
<note>Part of a larger sentence to describe how many reposts there are.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/reposts_count:dict/REPOSTS:dict/one:dict/:string" xml:space="preserve">
|
||||
<source>Repost</source>
|
||||
<target>Repost</target>
|
||||
<note>Part of a larger sentence to describe how many reposts there are.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/reposts_count:dict/REPOSTS:dict/other:dict/:string" xml:space="preserve">
|
||||
<source>Reposts</source>
|
||||
<target>Reposts</target>
|
||||
<note>Part of a larger sentence to describe how many reposts there are.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/sats_count:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
|
||||
<source>%1$#@SATS@</source>
|
||||
<target>%1$#@SATS@</target>
|
||||
<note>Amount of sats.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/sats_count:dict/SATS:dict/one:dict/:string" xml:space="preserve">
|
||||
<source>%2$@ sat</source>
|
||||
<target>%2$@ sat</target>
|
||||
<note>Amount of sats.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/sats_count:dict/SATS:dict/other:dict/:string" xml:space="preserve">
|
||||
<source>%2$@ sats</source>
|
||||
<target>%2$@ sats</target>
|
||||
<note>Amount of sats.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/tips_count:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
|
||||
<source>%#@TIPS@</source>
|
||||
<target>%#@TIPS@</target>
|
||||
<note>Part of a larger sentence to describe how many tip payments there are on a post.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/tips_count:dict/TIPS:dict/one:dict/:string" xml:space="preserve">
|
||||
<source>Tip</source>
|
||||
<target>Tip</target>
|
||||
<note>Part of a larger sentence to describe how many tip payments there are on a post.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/tips_count:dict/TIPS:dict/other:dict/:string" xml:space="preserve">
|
||||
<source>Tips</source>
|
||||
<target>Tips</target>
|
||||
<note>Part of a larger sentence to describe how many tip payments there are on a post.</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
||||
Binary file not shown.
+103
-9
@@ -2,6 +2,70 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>collapsed_event_view_other_notes</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>··· %#@NOTES@ ···</string>
|
||||
<key>NOTES</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%d other note</string>
|
||||
<key>other</key>
|
||||
<string>%d other notes</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>followers_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@FOLLOWERS@</string>
|
||||
<key>FOLLOWERS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Follower</string>
|
||||
<key>other</key>
|
||||
<string>Followers</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>reactions_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@REACTIONS@</string>
|
||||
<key>REACTIONS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Reaction</string>
|
||||
<key>other</key>
|
||||
<string>Reactions</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>relays_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@RELAYS@</string>
|
||||
<key>RELAYS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Relay</string>
|
||||
<key>other</key>
|
||||
<string>Relays</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>replying_to_one_and_others</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
@@ -15,7 +79,7 @@
|
||||
<key>zero</key>
|
||||
<string></string>
|
||||
<key>one</key>
|
||||
<string> & 1 other</string>
|
||||
<string> & %d other</string>
|
||||
<key>other</key>
|
||||
<string> & %d others</string>
|
||||
</dict>
|
||||
@@ -33,27 +97,57 @@
|
||||
<key>zero</key>
|
||||
<string></string>
|
||||
<key>one</key>
|
||||
<string> & 1 other</string>
|
||||
<string> & %d other</string>
|
||||
<key>other</key>
|
||||
<string> & %d others</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>collapsed_event_view_other_notes</key>
|
||||
<key>reposts_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>··· %#@NOTES@ ···</string>
|
||||
<key>NOTES</key>
|
||||
<string>%#@REPOSTS@</string>
|
||||
<key>REPOSTS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>zero</key>
|
||||
<string>0 other notes</string>
|
||||
<key>one</key>
|
||||
<string>1 other note</string>
|
||||
<string>Repost</string>
|
||||
<key>other</key>
|
||||
<string>%d other notes</string>
|
||||
<string>Reposts</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>sats_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%1$#@SATS@</string>
|
||||
<key>SATS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>@</string>
|
||||
<key>one</key>
|
||||
<string>%2$@ sat</string>
|
||||
<key>other</key>
|
||||
<string>%2$@ sats</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>tips_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@TIPS@</string>
|
||||
<key>TIPS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Tip</string>
|
||||
<key>other</key>
|
||||
<string>Tips</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
|
||||
@@ -30,11 +30,13 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="%@" xml:space="preserve">
|
||||
<source>%@</source>
|
||||
<note>Number of people following a user.</note>
|
||||
<note>Amount of time that has passed since reply quote event occurred.
|
||||
Abbreviated version of a nostr public key.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ %@" xml:space="preserve">
|
||||
<source>%@ %@</source>
|
||||
<note>Sentence composed of 2 variables to describe how many profiles a user is following. In source English, the first variable is the number of profiles being followed, and the second variable is 'Following'.</note>
|
||||
<note>Sentence composed of 2 variables to describe how many reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.
|
||||
Sentence composed of 2 variables to describe how many profiles a user is following. In source English, the first variable is the number of profiles being followed, and the second variable is 'Following'.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@. Creating an account doesn't require a phone number, email or name. Get started right away with zero friction." xml:space="preserve">
|
||||
<source>%@. Creating an account doesn't require a phone number, email or name. Get started right away with zero friction.</source>
|
||||
@@ -50,16 +52,13 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="%lld" xml:space="preserve">
|
||||
<source>%lld</source>
|
||||
<note>Number of profiles a user is following.</note>
|
||||
<note>Number of reposts.
|
||||
Number of profiles a user is following.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%lld/%lld" xml:space="preserve">
|
||||
<source>%lld/%lld</source>
|
||||
<note>Fraction of how many of the user's relay servers that are operational.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="&nbsp;" xml:space="preserve">
|
||||
<source>&nbsp;</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="'%@' at '%@' will be used for verification" xml:space="preserve">
|
||||
<source>'%@' at '%@' will be used for verification</source>
|
||||
<note>Description of how the nip05 identifier would be used for verification.</note>
|
||||
@@ -72,14 +71,6 @@
|
||||
<source>(Profile.displayName(profile: profile, pubkey: whos))'s Followers</source>
|
||||
<note>Navigation bar title for view that shows who is following a user.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="(formattedSats) sat" xml:space="preserve">
|
||||
<source>(formattedSats) sat</source>
|
||||
<note>Amount of 1 sat.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="(formattedSats) sats" xml:space="preserve">
|
||||
<source>(formattedSats) sats</source>
|
||||
<note>Amount of sats.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="(who) following" xml:space="preserve">
|
||||
<source>(who) following</source>
|
||||
<note>Navigation bar title for view that shows who a user is following.</note>
|
||||
@@ -121,9 +112,13 @@
|
||||
<source>Any</source>
|
||||
<note>Any amount of sats</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Are you sure you want to boost this post?" xml:space="preserve">
|
||||
<source>Are you sure you want to boost this post?</source>
|
||||
<note>Alert message to ask if user wants to boost a post.</note>
|
||||
<trans-unit id="Are you sure you want to repost this?" xml:space="preserve">
|
||||
<source>Are you sure you want to repost this?</source>
|
||||
<note>Alert message to ask if user wants to repost a post.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Banner Image" xml:space="preserve">
|
||||
<source>Banner Image</source>
|
||||
<note>Label for Banner Image section of user profile form.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Before we get started, you'll need to save your account info, otherwise you won't be able to login in the future if you ever uninstall Damus." xml:space="preserve">
|
||||
<source>Before we get started, you'll need to save your account info, otherwise you won't be able to login in the future if you ever uninstall Damus.</source>
|
||||
@@ -145,15 +140,6 @@
|
||||
<source>Blue Wallet</source>
|
||||
<note>Dropdown option label for Lightning wallet, Blue Wallet.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Boost" xml:space="preserve">
|
||||
<source>Boost</source>
|
||||
<note>Button to confirm boosting a post.
|
||||
Title of alert for confirming to boost a post.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Boosted" xml:space="preserve">
|
||||
<source>Boosted</source>
|
||||
<note>Text indicating that the post was boosted (i.e. re-shared).</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Breez" xml:space="preserve">
|
||||
<source>Breez</source>
|
||||
<note>Dropdown option label for Lightning wallet, Breez.</note>
|
||||
@@ -165,6 +151,7 @@
|
||||
<trans-unit id="Cancel" xml:space="preserve">
|
||||
<source>Cancel</source>
|
||||
<note>Button to cancel out of posting a note.
|
||||
Button to cancel out of reposting a post.
|
||||
Button to cancel out of view adding user inputted relay.
|
||||
Cancel out of logging out the user.</note>
|
||||
</trans-unit>
|
||||
@@ -277,10 +264,6 @@
|
||||
<source>Edit</source>
|
||||
<note>Button to edit user's profile.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Edit Profile" xml:space="preserve">
|
||||
<source>Edit Profile</source>
|
||||
<note>Title of navigation view for Edit Profile.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypted" xml:space="preserve">
|
||||
<source>Encrypted</source>
|
||||
<note>Heading indicating that this application keeps private messaging end-to-end encrypted.</note>
|
||||
@@ -346,6 +329,10 @@ Part of a larger sentence to describe how many profiles a user is following.</no
|
||||
<source>LNLink</source>
|
||||
<note>Dropdown option label for Lightning wallet, LNLink.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Left Handed" xml:space="preserve">
|
||||
<source>Left Handed</source>
|
||||
<note>Moves the post button to the left side of the screen</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Let's go!" xml:space="preserve">
|
||||
<source>Let's go!</source>
|
||||
<note>Button to complete account creation and start using the app.</note>
|
||||
@@ -364,7 +351,8 @@ Part of a larger sentence to describe how many profiles a user is following.</no
|
||||
</trans-unit>
|
||||
<trans-unit id="Login" xml:space="preserve">
|
||||
<source>Login</source>
|
||||
<note>Button to log into account.</note>
|
||||
<note>Button to log into account.
|
||||
Button to log into an account.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Logout" xml:space="preserve">
|
||||
<source>Logout</source>
|
||||
@@ -428,6 +416,10 @@ Part of a larger sentence to describe how many profiles a user is following.</no
|
||||
<source>PrivateKey</source>
|
||||
<note>Title of the secure field that holds the user's private key.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Profile" xml:space="preserve">
|
||||
<source>Profile</source>
|
||||
<note>Sidebar menu label for Profile view.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Profile Picture" xml:space="preserve">
|
||||
<source>Profile Picture</source>
|
||||
<note>Label for Profile Picture section of user profile form.</note>
|
||||
@@ -448,6 +440,10 @@ Part of a larger sentence to describe how many profiles a user is following.</no
|
||||
<source>Public key</source>
|
||||
<note>Label indicating that the text is a user's public account key.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Reactions" xml:space="preserve">
|
||||
<source>Reactions</source>
|
||||
<note>Navigation bar title for Reactions view.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Recommended Relays" xml:space="preserve">
|
||||
<source>Recommended Relays</source>
|
||||
<note>Section title for recommend relay servers that could be added as part of configuration</note>
|
||||
@@ -458,8 +454,7 @@ Part of a larger sentence to describe how many profiles a user is following.</no
|
||||
</trans-unit>
|
||||
<trans-unit id="Relays" xml:space="preserve">
|
||||
<source>Relays</source>
|
||||
<note>Header text for relay server list for configuration.
|
||||
Part of a larger sentence to describe how many relay servers a user is connected.</note>
|
||||
<note>Sidebar menu label for Relay servers view</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Reply to self" xml:space="preserve">
|
||||
<source>Reply to self</source>
|
||||
@@ -473,10 +468,23 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
<source>Replying to:</source>
|
||||
<note>Indicating that the user is replying to the following listed people.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repost" xml:space="preserve">
|
||||
<source>Repost</source>
|
||||
<note>Button to confirm reposting a post.
|
||||
Title of alert for confirming to repost a post.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Reposted" xml:space="preserve">
|
||||
<source>Reposted</source>
|
||||
<note>Text indicating that the post was reposted (i.e. re-shared).</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Reset" xml:space="preserve">
|
||||
<source>Reset</source>
|
||||
<note>Section title for resetting the user</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Retry" xml:space="preserve">
|
||||
<source>Retry</source>
|
||||
<note>Button to retry completing account creation after an error occurred.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="River" xml:space="preserve">
|
||||
<source>River</source>
|
||||
<note>Dropdown option label for Lightning wallet, River</note>
|
||||
@@ -519,7 +527,8 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
</trans-unit>
|
||||
<trans-unit id="Settings" xml:space="preserve">
|
||||
<source>Settings</source>
|
||||
<note>Navigation title for Settings view.</note>
|
||||
<note>Navigation title for Settings view.
|
||||
Sidebar menu label for accessing the app settings</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Share" xml:space="preserve">
|
||||
<source>Share</source>
|
||||
@@ -533,6 +542,10 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
<source>Show wallet selector</source>
|
||||
<note>Toggle to show or hide selection of wallet.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Sign out" xml:space="preserve">
|
||||
<source>Sign out</source>
|
||||
<note>Sidebar menu label to sign out of the account.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Strike" xml:space="preserve">
|
||||
<source>Strike</source>
|
||||
<note>Dropdown option label for Lightning wallet, Strike.</note>
|
||||
@@ -583,6 +596,10 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
<note>Label for Username section of user profile form.
|
||||
Label to prompt username entry.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Wallet" xml:space="preserve">
|
||||
<source>Wallet</source>
|
||||
<note>Sidebar menu label for Wallet view.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Wallet Of Satoshi" xml:space="preserve">
|
||||
<source>Wallet Of Satoshi</source>
|
||||
<note>Dropdown option label for Lightning wallet, Wallet Of Satoshi.</note>
|
||||
@@ -619,6 +636,10 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
<source>collapsed_event_view_other_notes</source>
|
||||
<note>Text to indicate that the thread was collapsed and that there are other notes to view if tapped. (Key in .stringsdict)</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="followers_count" translate="no" xml:space="preserve">
|
||||
<source>followers_count</source>
|
||||
<note>Part of a larger sentence to describe how many people are following a user. (Key in .stringsdict)</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="https://example.com/pic.jpg" xml:space="preserve">
|
||||
<source>https://example.com/pic.jpg</source>
|
||||
<note>Placeholder example text for profile picture URL.</note>
|
||||
@@ -647,6 +668,14 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
<source>optional</source>
|
||||
<note>Label indicating that a form input is optional.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="reactions_count" translate="no" xml:space="preserve">
|
||||
<source>reactions_count</source>
|
||||
<note>Part of a larger sentence to describe how many reactions there are on a post. (Key in .stringsdict)</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="relays_count" translate="no" xml:space="preserve">
|
||||
<source>relays_count</source>
|
||||
<note>Part of a larger sentence to describe how many relay servers a user is connected. (Key in .stringsdict)</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="replying_to_one_and_others" translate="no" xml:space="preserve">
|
||||
<source>replying_to_one_and_others</source>
|
||||
<note>Label to indicate that the user is replying to 1 user and others. (Key in .stringsdict)</note>
|
||||
@@ -655,10 +684,26 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
<source>replying_to_two_and_others</source>
|
||||
<note>Label to indicate that the user is replying to 2 users and others. (Key in .stringsdict)</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="reposts_count" translate="no" xml:space="preserve">
|
||||
<source>reposts_count</source>
|
||||
<note>Part of a larger sentence to describe how many reposts there are. (Key in .stringsdict)</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="satoshi" xml:space="preserve">
|
||||
<source>satoshi</source>
|
||||
<note>Example username of Bitcoin creator(s), Satoshi Nakamoto.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="sats_count" translate="no" xml:space="preserve">
|
||||
<source>sats_count</source>
|
||||
<note>Amount of sats. (Key in .stringsdict)</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="tips_count" translate="no" xml:space="preserve">
|
||||
<source>tips_count</source>
|
||||
<note>Part of a larger sentence to describe how many tip payments there are on a post. (Key in .stringsdict)</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="u{00A0}" xml:space="preserve">
|
||||
<source>u{00A0}</source>
|
||||
<note>Non-breaking space character to fill in blank space next to event action button icons.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="wss://some.relay.com" xml:space="preserve">
|
||||
<source>wss://some.relay.com</source>
|
||||
<note>Placeholder example for relay server address.</note>
|
||||
@@ -667,10 +712,6 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
<source>you</source>
|
||||
<note>You, in this context, is the person who controls their own social network. You is used in the context of a larger sentence that welcomes the reader to the social network that they control themself.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="🤙" xml:space="preserve">
|
||||
<source>🤙</source>
|
||||
<note>Button with emoji to like an event.</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="damus/en-US.lproj/Localizable.stringsdict" source-language="en-US" target-language="es-419" datatype="plaintext">
|
||||
@@ -679,8 +720,8 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
</header>
|
||||
<body>
|
||||
<trans-unit id="/collapsed_event_view_other_notes:dict/NOTES:dict/one:dict/:string" xml:space="preserve">
|
||||
<source>1 other note</source>
|
||||
<target>1 other note</target>
|
||||
<source>%d other note</source>
|
||||
<target>%d other note</target>
|
||||
<note>Text to indicate that the thread was collapsed and that there are other notes to view if tapped.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/collapsed_event_view_other_notes:dict/NOTES:dict/other:dict/:string" xml:space="preserve">
|
||||
@@ -688,24 +729,64 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
<target>%d other notes</target>
|
||||
<note>Text to indicate that the thread was collapsed and that there are other notes to view if tapped.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/collapsed_event_view_other_notes:dict/NOTES:dict/zero:dict/:string" xml:space="preserve">
|
||||
<source>0 other notes</source>
|
||||
<target>0 other notes</target>
|
||||
<note>Text to indicate that the thread was collapsed and that there are other notes to view if tapped.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/collapsed_event_view_other_notes:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
|
||||
<source>··· %#@NOTES@ ···</source>
|
||||
<target>··· %#@NOTES@ ···</target>
|
||||
<note>Text to indicate that the thread was collapsed and that there are other notes to view if tapped.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/followers_count:dict/FOLLOWERS:dict/one:dict/:string" xml:space="preserve">
|
||||
<source>Follower</source>
|
||||
<target>Follower</target>
|
||||
<note>Part of a larger sentence to describe how many people are following a user.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/followers_count:dict/FOLLOWERS:dict/other:dict/:string" xml:space="preserve">
|
||||
<source>Followers</source>
|
||||
<target>Followers</target>
|
||||
<note>Part of a larger sentence to describe how many people are following a user.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/followers_count:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
|
||||
<source>%#@FOLLOWERS@</source>
|
||||
<target>%#@FOLLOWERS@</target>
|
||||
<note>Part of a larger sentence to describe how many people are following a user.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/reactions_count:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
|
||||
<source>%#@REACTIONS@</source>
|
||||
<target>%#@REACTIONS@</target>
|
||||
<note>Part of a larger sentence to describe how many reactions there are on a post.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/reactions_count:dict/REACTIONS:dict/one:dict/:string" xml:space="preserve">
|
||||
<source>Reaction</source>
|
||||
<target>Reaction</target>
|
||||
<note>Part of a larger sentence to describe how many reactions there are on a post.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/reactions_count:dict/REACTIONS:dict/other:dict/:string" xml:space="preserve">
|
||||
<source>Reactions</source>
|
||||
<target>Reactions</target>
|
||||
<note>Part of a larger sentence to describe how many reactions there are on a post.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/relays_count:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
|
||||
<source>%#@RELAYS@</source>
|
||||
<target>%#@RELAYS@</target>
|
||||
<note>Part of a larger sentence to describe how many relay servers a user is connected.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/relays_count:dict/RELAYS:dict/one:dict/:string" xml:space="preserve">
|
||||
<source>Relay</source>
|
||||
<target>Relay</target>
|
||||
<note>Part of a larger sentence to describe how many relay servers a user is connected.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/relays_count:dict/RELAYS:dict/other:dict/:string" xml:space="preserve">
|
||||
<source>Relays</source>
|
||||
<target>Relays</target>
|
||||
<note>Part of a larger sentence to describe how many relay servers a user is connected.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/replying_to_one_and_others:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
|
||||
<source>Replying to %@%#@OTHERS@</source>
|
||||
<target>Replying to %@%#@OTHERS@</target>
|
||||
<note>Label to indicate that the user is replying to 1 user and others.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/replying_to_one_and_others:dict/OTHERS:dict/one:dict/:string" xml:space="preserve">
|
||||
<source> & 1 other</source>
|
||||
<target> & 1 other</target>
|
||||
<source> & %d other</source>
|
||||
<target> & %d other</target>
|
||||
<note>Label to indicate that the user is replying to 1 user and others.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/replying_to_one_and_others:dict/OTHERS:dict/other:dict/:string" xml:space="preserve">
|
||||
@@ -724,8 +805,8 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
<note>Label to indicate that the user is replying to 2 users and others.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/replying_to_two_and_others:dict/OTHERS:dict/one:dict/:string" xml:space="preserve">
|
||||
<source> & 1 other</source>
|
||||
<target> & 1 other</target>
|
||||
<source> & %d other</source>
|
||||
<target> & %d other</target>
|
||||
<note>Label to indicate that the user is replying to 2 users and others.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/replying_to_two_and_others:dict/OTHERS:dict/other:dict/:string" xml:space="preserve">
|
||||
@@ -738,6 +819,51 @@ Part of a larger sentence to describe how many relay servers a user is connected
|
||||
<target/>
|
||||
<note>Label to indicate that the user is replying to 2 users and others.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/reposts_count:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
|
||||
<source>%#@REPOSTS@</source>
|
||||
<target>%#@REPOSTS@</target>
|
||||
<note>Part of a larger sentence to describe how many reposts there are.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/reposts_count:dict/REPOSTS:dict/one:dict/:string" xml:space="preserve">
|
||||
<source>Repost</source>
|
||||
<target>Repost</target>
|
||||
<note>Part of a larger sentence to describe how many reposts there are.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/reposts_count:dict/REPOSTS:dict/other:dict/:string" xml:space="preserve">
|
||||
<source>Reposts</source>
|
||||
<target>Reposts</target>
|
||||
<note>Part of a larger sentence to describe how many reposts there are.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/sats_count:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
|
||||
<source>%1$#@SATS@</source>
|
||||
<target>%1$#@SATS@</target>
|
||||
<note>Amount of sats.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/sats_count:dict/SATS:dict/one:dict/:string" xml:space="preserve">
|
||||
<source>%2$@ sat</source>
|
||||
<target>%2$@ sat</target>
|
||||
<note>Amount of sats.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/sats_count:dict/SATS:dict/other:dict/:string" xml:space="preserve">
|
||||
<source>%2$@ sats</source>
|
||||
<target>%2$@ sats</target>
|
||||
<note>Amount of sats.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/tips_count:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
|
||||
<source>%#@TIPS@</source>
|
||||
<target>%#@TIPS@</target>
|
||||
<note>Part of a larger sentence to describe how many tip payments there are on a post.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/tips_count:dict/TIPS:dict/one:dict/:string" xml:space="preserve">
|
||||
<source>Tip</source>
|
||||
<target>Tip</target>
|
||||
<note>Part of a larger sentence to describe how many tip payments there are on a post.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="/tips_count:dict/TIPS:dict/other:dict/:string" xml:space="preserve">
|
||||
<source>Tips</source>
|
||||
<target>Tips</target>
|
||||
<note>Part of a larger sentence to describe how many tip payments there are on a post.</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
||||
BIN
Binary file not shown.
+103
-9
@@ -2,6 +2,70 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>collapsed_event_view_other_notes</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>··· %#@NOTES@ ···</string>
|
||||
<key>NOTES</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%d other note</string>
|
||||
<key>other</key>
|
||||
<string>%d other notes</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>followers_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@FOLLOWERS@</string>
|
||||
<key>FOLLOWERS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Follower</string>
|
||||
<key>other</key>
|
||||
<string>Followers</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>reactions_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@REACTIONS@</string>
|
||||
<key>REACTIONS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Reaction</string>
|
||||
<key>other</key>
|
||||
<string>Reactions</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>relays_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@RELAYS@</string>
|
||||
<key>RELAYS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Relay</string>
|
||||
<key>other</key>
|
||||
<string>Relays</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>replying_to_one_and_others</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
@@ -15,7 +79,7 @@
|
||||
<key>zero</key>
|
||||
<string></string>
|
||||
<key>one</key>
|
||||
<string> & 1 other</string>
|
||||
<string> & %d other</string>
|
||||
<key>other</key>
|
||||
<string> & %d others</string>
|
||||
</dict>
|
||||
@@ -33,27 +97,57 @@
|
||||
<key>zero</key>
|
||||
<string></string>
|
||||
<key>one</key>
|
||||
<string> & 1 other</string>
|
||||
<string> & %d other</string>
|
||||
<key>other</key>
|
||||
<string> & %d others</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>collapsed_event_view_other_notes</key>
|
||||
<key>reposts_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>··· %#@NOTES@ ···</string>
|
||||
<key>NOTES</key>
|
||||
<string>%#@REPOSTS@</string>
|
||||
<key>REPOSTS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>zero</key>
|
||||
<string>0 other notes</string>
|
||||
<key>one</key>
|
||||
<string>1 other note</string>
|
||||
<string>Repost</string>
|
||||
<key>other</key>
|
||||
<string>%d other notes</string>
|
||||
<string>Reposts</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>sats_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%1$#@SATS@</string>
|
||||
<key>SATS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>@</string>
|
||||
<key>one</key>
|
||||
<string>%2$@ sat</string>
|
||||
<key>other</key>
|
||||
<string>%2$@ sats</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>tips_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@TIPS@</string>
|
||||
<key>TIPS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Tip</string>
|
||||
<key>other</key>
|
||||
<string>Tips</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
|
||||
@@ -116,6 +116,13 @@
|
||||
4CB55EF3295E5D59007FD187 /* RecommendedRelayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB55EF2295E5D59007FD187 /* RecommendedRelayView.swift */; };
|
||||
4CB55EF5295E679D007FD187 /* UserRelaysView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB55EF4295E679D007FD187 /* UserRelaysView.swift */; };
|
||||
4CB8838629656C8B00DC99E7 /* NIP05.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB8838529656C8B00DC99E7 /* NIP05.swift */; };
|
||||
4CB88389296AF99A00DC99E7 /* EventDetailBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB88388296AF99A00DC99E7 /* EventDetailBar.swift */; };
|
||||
4CB8838B296F6E1E00DC99E7 /* NIP05Badge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB8838A296F6E1E00DC99E7 /* NIP05Badge.swift */; };
|
||||
4CB8838D296F710400DC99E7 /* Reposted.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB8838C296F710400DC99E7 /* Reposted.swift */; };
|
||||
4CB8838F296F781C00DC99E7 /* ReactionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB8838E296F781C00DC99E7 /* ReactionsView.swift */; };
|
||||
4CB88393296F798300DC99E7 /* ReactionsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB88392296F798300DC99E7 /* ReactionsModel.swift */; };
|
||||
4CB88396296F7F8B00DC99E7 /* ReactionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB88395296F7F8B00DC99E7 /* ReactionView.swift */; };
|
||||
4CB8839A297322D200DC99E7 /* DMTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB88399297322D200DC99E7 /* DMTests.swift */; };
|
||||
4CD7641B28A1641400B6928F /* EndBlock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CD7641A28A1641400B6928F /* EndBlock.swift */; };
|
||||
4CE4F8CD281352B30009DFBB /* Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE4F8CC281352B30009DFBB /* Notifications.swift */; };
|
||||
4CE4F9DE2852768D00C00DD9 /* ConfigView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE4F9DD2852768D00C00DD9 /* ConfigView.swift */; };
|
||||
@@ -141,6 +148,10 @@
|
||||
647D9A8D2968520300A295DE /* SideMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 647D9A8C2968520300A295DE /* SideMenuView.swift */; };
|
||||
64FBD06F296255C400D9D3B2 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64FBD06E296255C400D9D3B2 /* Theme.swift */; };
|
||||
6C7DE41F2955169800E66263 /* Vault in Frameworks */ = {isa = PBXBuildFile; productRef = 6C7DE41E2955169800E66263 /* Vault */; };
|
||||
7C45AE6D297352F90031D7BC /* SVGKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7C45AE6C297352F90031D7BC /* SVGKit */; };
|
||||
7C45AE6F297352F90031D7BC /* SVGKitSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 7C45AE6E297352F90031D7BC /* SVGKitSwift */; };
|
||||
7C45AE71297353390031D7BC /* KFImageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C45AE70297353390031D7BC /* KFImageModel.swift */; };
|
||||
9609F058296E220800069BF3 /* BannerImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9609F057296E220800069BF3 /* BannerImageView.swift */; };
|
||||
BA693074295D649800ADDB87 /* UserSettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA693073295D649800ADDB87 /* UserSettingsStore.swift */; };
|
||||
BAB68BED29543FA3007BA466 /* SelectWalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */; };
|
||||
DD597CBD2963D85A00C64D32 /* MarkdownTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD597CBC2963D85A00C64D32 /* MarkdownTests.swift */; };
|
||||
@@ -308,6 +319,13 @@
|
||||
4CB55EF2295E5D59007FD187 /* RecommendedRelayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendedRelayView.swift; sourceTree = "<group>"; };
|
||||
4CB55EF4295E679D007FD187 /* UserRelaysView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserRelaysView.swift; sourceTree = "<group>"; };
|
||||
4CB8838529656C8B00DC99E7 /* NIP05.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NIP05.swift; sourceTree = "<group>"; };
|
||||
4CB88388296AF99A00DC99E7 /* EventDetailBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventDetailBar.swift; sourceTree = "<group>"; };
|
||||
4CB8838A296F6E1E00DC99E7 /* NIP05Badge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NIP05Badge.swift; sourceTree = "<group>"; };
|
||||
4CB8838C296F710400DC99E7 /* Reposted.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reposted.swift; sourceTree = "<group>"; };
|
||||
4CB8838E296F781C00DC99E7 /* ReactionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionsView.swift; sourceTree = "<group>"; };
|
||||
4CB88392296F798300DC99E7 /* ReactionsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionsModel.swift; sourceTree = "<group>"; };
|
||||
4CB88395296F7F8B00DC99E7 /* ReactionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionView.swift; sourceTree = "<group>"; };
|
||||
4CB88399297322D200DC99E7 /* DMTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DMTests.swift; sourceTree = "<group>"; };
|
||||
4CD7641A28A1641400B6928F /* EndBlock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EndBlock.swift; sourceTree = "<group>"; };
|
||||
4CE4F8CC281352B30009DFBB /* Notifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifications.swift; sourceTree = "<group>"; };
|
||||
4CE4F9DD2852768D00C00DD9 /* ConfigView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigView.swift; sourceTree = "<group>"; };
|
||||
@@ -335,6 +353,8 @@
|
||||
4FE60CDC295E1C5E00105A1F /* Wallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wallet.swift; sourceTree = "<group>"; };
|
||||
647D9A8C2968520300A295DE /* SideMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideMenuView.swift; sourceTree = "<group>"; };
|
||||
64FBD06E296255C400D9D3B2 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
|
||||
7C45AE70297353390031D7BC /* KFImageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KFImageModel.swift; sourceTree = "<group>"; };
|
||||
9609F057296E220800069BF3 /* BannerImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BannerImageView.swift; sourceTree = "<group>"; };
|
||||
BA693073295D649800ADDB87 /* UserSettingsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettingsStore.swift; sourceTree = "<group>"; };
|
||||
BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectWalletView.swift; sourceTree = "<group>"; };
|
||||
DD597CBC2963D85A00C64D32 /* MarkdownTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarkdownTests.swift; sourceTree = "<group>"; };
|
||||
@@ -347,6 +367,8 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
7C45AE6F297352F90031D7BC /* SVGKitSwift in Frameworks */,
|
||||
7C45AE6D297352F90031D7BC /* SVGKit in Frameworks */,
|
||||
4C06670428FC7EC500038D2A /* Kingfisher in Frameworks */,
|
||||
6C7DE41F2955169800E66263 /* Vault in Frameworks */,
|
||||
4CE6DF1227F7A2B300C66700 /* Starscream in Frameworks */,
|
||||
@@ -465,6 +487,8 @@
|
||||
4C99737A28C92A9200E53835 /* ChatroomMetadata.swift */,
|
||||
BA693073295D649800ADDB87 /* UserSettingsStore.swift */,
|
||||
4FE60CDC295E1C5E00105A1F /* Wallet.swift */,
|
||||
4CB88392296F798300DC99E7 /* ReactionsModel.swift */,
|
||||
7C45AE70297353390031D7BC /* KFImageModel.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
@@ -472,6 +496,8 @@
|
||||
4C75EFA227FA576C0006080F /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4CB88394296F7F8100DC99E7 /* Reactions */,
|
||||
4CB88387296AF97C00DC99E7 /* ActionBar */,
|
||||
4CE4F9E228528C5200C00DD9 /* AddRelayView.swift */,
|
||||
4C363A8728236948006E126D /* BlocksView.swift */,
|
||||
4C285C8128385570008A31F1 /* CarouselView.swift */,
|
||||
@@ -484,7 +510,6 @@
|
||||
4C216F33286F5ACD00040376 /* DMView.swift */,
|
||||
E990020E2955F837003BBC5A /* EditMetadataView.swift */,
|
||||
3169CAE4294E699400EE4006 /* Empty Views */,
|
||||
4CEE2B01280B39E800AB5EEF /* EventActionBar.swift */,
|
||||
4CEE2AF0280B216B00AB5EEF /* EventDetailView.swift */,
|
||||
4C75EFB82804A2740006080F /* EventView.swift */,
|
||||
4C3AC79E2833115300E1F516 /* FollowButtonView.swift */,
|
||||
@@ -516,6 +541,8 @@
|
||||
4CA2EF9F280E37AC0044ACD8 /* TimelineView.swift */,
|
||||
4CB55EF4295E679D007FD187 /* UserRelaysView.swift */,
|
||||
647D9A8C2968520300A295DE /* SideMenuView.swift */,
|
||||
9609F057296E220800069BF3 /* BannerImageView.swift */,
|
||||
4CB8838E296F781C00DC99E7 /* ReactionsView.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
@@ -561,6 +588,23 @@
|
||||
path = Util;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4CB88387296AF97C00DC99E7 /* ActionBar */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4CEE2B01280B39E800AB5EEF /* EventActionBar.swift */,
|
||||
4CB88388296AF99A00DC99E7 /* EventDetailBar.swift */,
|
||||
);
|
||||
path = ActionBar;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4CB88394296F7F8100DC99E7 /* Reactions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4CB88395296F7F8B00DC99E7 /* ReactionView.swift */,
|
||||
);
|
||||
path = Reactions;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4CE4F9DF285287A000C00DD9 /* Components */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -570,6 +614,8 @@
|
||||
4C06670528FCB08600038D2A /* ImageCarousel.swift */,
|
||||
4C3EA67C28FFBBA200C48A62 /* InvoicesView.swift */,
|
||||
4C3EA67E28FFC01D00C48A62 /* InvoiceView.swift */,
|
||||
4CB8838A296F6E1E00DC99E7 /* NIP05Badge.swift */,
|
||||
4CB8838C296F710400DC99E7 /* Reposted.swift */,
|
||||
);
|
||||
path = Components;
|
||||
sourceTree = "<group>";
|
||||
@@ -633,6 +679,7 @@
|
||||
4CE6DEF727F7A08200C66700 /* damusTests.swift */,
|
||||
4C3EA67A28FF7B3900C48A62 /* InvoiceTests.swift */,
|
||||
3ACBCB77295FE5C70037388A /* TimeAgoTests.swift */,
|
||||
4CB88399297322D200DC99E7 /* DMTests.swift */,
|
||||
);
|
||||
path = damusTests;
|
||||
sourceTree = "<group>";
|
||||
@@ -675,6 +722,8 @@
|
||||
4C649880286E0EE300EAE2B3 /* secp256k1 */,
|
||||
4C06670328FC7EC500038D2A /* Kingfisher */,
|
||||
6C7DE41E2955169800E66263 /* Vault */,
|
||||
7C45AE6C297352F90031D7BC /* SVGKit */,
|
||||
7C45AE6E297352F90031D7BC /* SVGKitSwift */,
|
||||
);
|
||||
productName = damus;
|
||||
productReference = 4CE6DEE327F7A08100C66700 /* damus.app */;
|
||||
@@ -755,6 +804,7 @@
|
||||
4C64987F286E0EE300EAE2B3 /* XCRemoteSwiftPackageReference "secp256k1" */,
|
||||
4C06670228FC7EC500038D2A /* XCRemoteSwiftPackageReference "Kingfisher" */,
|
||||
6C7DE41D2955169800E66263 /* XCRemoteSwiftPackageReference "Vault" */,
|
||||
7C45AE6B297352F90031D7BC /* XCRemoteSwiftPackageReference "SVGKit" */,
|
||||
);
|
||||
productRefGroup = 4CE6DEE427F7A08100C66700 /* Products */;
|
||||
projectDirPath = "";
|
||||
@@ -812,6 +862,7 @@
|
||||
4C363A8C28236B92006E126D /* PubkeyView.swift in Sources */,
|
||||
4C5C7E68284ED36500A22DF5 /* SearchHomeModel.swift in Sources */,
|
||||
4C75EFB728049D990006080F /* RelayPool.swift in Sources */,
|
||||
4CB8838D296F710400DC99E7 /* Reposted.swift in Sources */,
|
||||
4C3EA67728FF7A9800C48A62 /* talstr.c in Sources */,
|
||||
4CE6DEE927F7A08100C66700 /* ContentView.swift in Sources */,
|
||||
4CEE2AF5280B29E600AB5EEF /* TimeAgo.swift in Sources */,
|
||||
@@ -833,6 +884,7 @@
|
||||
4C75EFA627FF87A20006080F /* Nostr.swift in Sources */,
|
||||
4CE4F9DE2852768D00C00DD9 /* ConfigView.swift in Sources */,
|
||||
4C285C8E28399BFE008A31F1 /* SaveKeysView.swift in Sources */,
|
||||
4CB8838F296F781C00DC99E7 /* ReactionsView.swift in Sources */,
|
||||
4C649844285A952100EAE2B3 /* LocalUserConfig.swift in Sources */,
|
||||
4C75EFB328049D640006080F /* NostrEvent.swift in Sources */,
|
||||
4CA2EFA0280E37AC0044ACD8 /* TimelineView.swift in Sources */,
|
||||
@@ -841,6 +893,7 @@
|
||||
4C363A9A28283854006E126D /* Reply.swift in Sources */,
|
||||
BA693074295D649800ADDB87 /* UserSettingsStore.swift in Sources */,
|
||||
4C90BD18283A9EE5008EE7EF /* LoginView.swift in Sources */,
|
||||
4CB8838B296F6E1E00DC99E7 /* NIP05Badge.swift in Sources */,
|
||||
4C3EA66828FF5F9900C48A62 /* hex.c in Sources */,
|
||||
E9E4ED0B295867B900DD7078 /* ThreadV2View.swift in Sources */,
|
||||
4C3BEFDC281DCE6100B3DE84 /* Liked.swift in Sources */,
|
||||
@@ -851,6 +904,7 @@
|
||||
4C3EA67F28FFC01D00C48A62 /* InvoiceView.swift in Sources */,
|
||||
4CEE2B02280B39E800AB5EEF /* EventActionBar.swift in Sources */,
|
||||
4C3BEFE0281DE1ED00B3DE84 /* DamusState.swift in Sources */,
|
||||
7C45AE71297353390031D7BC /* KFImageModel.swift in Sources */,
|
||||
4C0A3F8F280F640A000448DE /* ThreadModel.swift in Sources */,
|
||||
4C3AC79F2833115300E1F516 /* FollowButtonView.swift in Sources */,
|
||||
4C3BEFD22819DB9B00B3DE84 /* ProfileModel.swift in Sources */,
|
||||
@@ -867,6 +921,7 @@
|
||||
4C285C8C28398BC7008A31F1 /* Keys.swift in Sources */,
|
||||
4CACA9DC280C38C000D9BBE8 /* Profiles.swift in Sources */,
|
||||
4C633352283D419F00B1C9C3 /* SignalModel.swift in Sources */,
|
||||
9609F058296E220800069BF3 /* BannerImageView.swift in Sources */,
|
||||
4C363A94282704FA006E126D /* Post.swift in Sources */,
|
||||
4C216F32286E388800040376 /* DMChatView.swift in Sources */,
|
||||
4C3EA67928FF7ABF00C48A62 /* list.c in Sources */,
|
||||
@@ -880,6 +935,8 @@
|
||||
4C3EA66528FF5F6800C48A62 /* mem.c in Sources */,
|
||||
4C3EA64128FF553900C48A62 /* hash_u5.c in Sources */,
|
||||
4C3EA64F28FF59F200C48A62 /* tal.c in Sources */,
|
||||
4CB88393296F798300DC99E7 /* ReactionsModel.swift in Sources */,
|
||||
4CB88396296F7F8B00DC99E7 /* ReactionView.swift in Sources */,
|
||||
4C8682872814DE470026224F /* ProfileView.swift in Sources */,
|
||||
4C5F9114283D694D0052CD1C /* FollowTarget.swift in Sources */,
|
||||
4CB8838629656C8B00DC99E7 /* NIP05.swift in Sources */,
|
||||
@@ -902,6 +959,7 @@
|
||||
4C363A922825FCF2006E126D /* ProfileUpdate.swift in Sources */,
|
||||
4C0A3F95280F6C78000448DE /* ReplyQuoteView.swift in Sources */,
|
||||
4C3BEFDA281DCA1400B3DE84 /* LikeCounter.swift in Sources */,
|
||||
4CB88389296AF99A00DC99E7 /* EventDetailBar.swift in Sources */,
|
||||
4C3AC79B28306D7B00E1F516 /* Contacts.swift in Sources */,
|
||||
4C3EA63D28FF52D600C48A62 /* bolt11.c in Sources */,
|
||||
4CB55EF3295E5D59007FD187 /* RecommendedRelayView.swift in Sources */,
|
||||
@@ -933,6 +991,7 @@
|
||||
DD597CBD2963D85A00C64D32 /* MarkdownTests.swift in Sources */,
|
||||
4C3EA67B28FF7B3900C48A62 /* InvoiceTests.swift in Sources */,
|
||||
4C363A9E2828A822006E126D /* ReplyTests.swift in Sources */,
|
||||
4CB8839A297322D200DC99E7 /* DMTests.swift in Sources */,
|
||||
4C363AA02828A8DD006E126D /* LikeTests.swift in Sources */,
|
||||
4C90BD1C283AC38E008EE7EF /* Bech32Tests.swift in Sources */,
|
||||
4CE6DEF827F7A08200C66700 /* damusTests.swift in Sources */,
|
||||
@@ -1104,7 +1163,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = damus/damus.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 5;
|
||||
CURRENT_PROJECT_VERSION = 6;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"damus/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = XK7H4JAB3D;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -1112,6 +1171,7 @@
|
||||
INFOPLIST_FILE = damus/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Damus;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||
INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "\"Granting Damus access to your photo library allows you to save photos.";
|
||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||
@@ -1144,7 +1204,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = damus/damus.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 5;
|
||||
CURRENT_PROJECT_VERSION = 6;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"damus/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = XK7H4JAB3D;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -1152,6 +1212,7 @@
|
||||
INFOPLIST_FILE = damus/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Damus;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||
INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "\"Granting Damus access to your photo library allows you to save photos.";
|
||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||
@@ -1325,6 +1386,14 @@
|
||||
minimumVersion = 1.0.0;
|
||||
};
|
||||
};
|
||||
7C45AE6B297352F90031D7BC /* XCRemoteSwiftPackageReference "SVGKit" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/SVGKit/SVGKit";
|
||||
requirement = {
|
||||
kind = revision;
|
||||
revision = e1f13e27b1e4c0ffe20e7d8d3984bf49c2a584d0;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
@@ -1348,6 +1417,16 @@
|
||||
package = 6C7DE41D2955169800E66263 /* XCRemoteSwiftPackageReference "Vault" */;
|
||||
productName = Vault;
|
||||
};
|
||||
7C45AE6C297352F90031D7BC /* SVGKit */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 7C45AE6B297352F90031D7BC /* XCRemoteSwiftPackageReference "SVGKit" */;
|
||||
productName = SVGKit;
|
||||
};
|
||||
7C45AE6E297352F90031D7BC /* SVGKitSwift */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 7C45AE6B297352F90031D7BC /* XCRemoteSwiftPackageReference "SVGKit" */;
|
||||
productName = SVGKitSwift;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = 4CE6DEDB27F7A08100C66700 /* Project object */;
|
||||
|
||||
@@ -26,6 +26,14 @@
|
||||
"version" : "4.0.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "svgkit",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/SVGKit/SVGKit",
|
||||
"state" : {
|
||||
"revision" : "e1f13e27b1e4c0ffe20e7d8d3984bf49c2a584d0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "vault",
|
||||
"kind" : "remoteSourceControl",
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "shaka-full.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 0.000000 -0.073975 cm
|
||||
1.000000 1.000000 1.000000 scn
|
||||
1.295334 8.661732 m
|
||||
3.613694 8.367855 l
|
||||
4.475733 8.733568 5.268113 9.771931 5.474915 10.327032 c
|
||||
6.083156 11.959681 5.507567 14.604573 5.474915 15.061715 c
|
||||
5.448792 15.427428 6.008246 15.693006 6.291239 15.780080 c
|
||||
7.571236 15.858447 8.508359 14.876789 8.642253 13.984165 c
|
||||
8.740212 13.331103 8.576948 11.752880 8.381030 10.849482 c
|
||||
8.979668 10.936556 10.980525 10.901726 11.868687 10.849482 c
|
||||
12.756847 10.797236 13.474895 10.196423 14.193260 9.412750 c
|
||||
14.767952 8.237244 13.953805 7.725680 13.474895 7.616838 c
|
||||
13.834077 7.257654 l
|
||||
14.781013 5.918882 13.649043 5.178749 13.115711 5.004600 c
|
||||
13.474895 4.743376 l
|
||||
14.487136 3.763786 13.246323 2.751544 13.017752 2.882155 c
|
||||
11.058574 3.176033 l
|
||||
15.499378 1.673996 l
|
||||
16.054478 0.400530 15.074889 0.073999 14.781013 0.073999 c
|
||||
8.576947 1.673996 l
|
||||
6.291239 1.673996 5.311650 1.869914 4.299407 2.163791 c
|
||||
4.157911 2.131138 3.659409 1.987464 2.797370 1.673996 c
|
||||
1.935332 1.360527 1.219143 2.087601 0.968804 2.490320 c
|
||||
-0.285071 4.083785 -0.467927 7.257655 1.295334 8.661732 c
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
1149
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 15.666626 15.710510 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000001239 00000 n
|
||||
0000001262 00000 n
|
||||
0000001435 00000 n
|
||||
0000001509 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
1568
|
||||
%%EOF
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "shaka-line.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 0.474731 -0.563965 cm
|
||||
1.000000 1.000000 1.000000 scn
|
||||
3.613694 9.332577 m
|
||||
3.553993 8.861599 l
|
||||
3.637261 8.851044 3.721838 8.862753 3.799107 8.895533 c
|
||||
3.613694 9.332577 l
|
||||
h
|
||||
1.295334 9.626453 m
|
||||
1.355035 10.097433 l
|
||||
1.227973 10.113539 1.099794 10.077623 0.999601 9.997839 c
|
||||
1.295334 9.626453 l
|
||||
h
|
||||
0.968804 3.455042 m
|
||||
1.372000 3.705677 l
|
||||
1.362764 3.720535 1.352713 3.734872 1.341894 3.748621 c
|
||||
0.968804 3.455042 l
|
||||
h
|
||||
4.299407 3.128512 m
|
||||
4.431771 3.584435 l
|
||||
4.353942 3.607030 4.271623 3.609325 4.192656 3.591103 c
|
||||
4.299407 3.128512 l
|
||||
h
|
||||
8.576947 2.638718 m
|
||||
8.695503 3.098424 l
|
||||
8.656776 3.108411 8.616942 3.113465 8.576947 3.113465 c
|
||||
8.576947 2.638718 l
|
||||
h
|
||||
14.781013 1.038721 m
|
||||
14.662457 0.579016 l
|
||||
14.701184 0.569027 14.741018 0.563974 14.781013 0.563974 c
|
||||
14.781013 1.038721 l
|
||||
h
|
||||
15.499378 2.638718 m
|
||||
15.934578 2.828420 l
|
||||
15.881091 2.951125 15.778289 3.045548 15.651489 3.088437 c
|
||||
15.499378 2.638718 l
|
||||
h
|
||||
11.058574 4.140755 m
|
||||
11.128998 4.610250 l
|
||||
10.885809 4.646729 10.655017 4.491467 10.597156 4.252461 c
|
||||
10.539293 4.013455 10.673516 3.769826 10.906463 3.691035 c
|
||||
11.058574 4.140755 l
|
||||
h
|
||||
13.017752 3.846877 m
|
||||
13.253292 4.259073 l
|
||||
13.202273 4.288227 13.146286 4.307655 13.088176 4.316372 c
|
||||
13.017752 3.846877 l
|
||||
h
|
||||
13.474895 5.708097 m
|
||||
13.805044 6.049252 l
|
||||
13.789093 6.064689 13.772079 6.078987 13.754128 6.092043 c
|
||||
13.474895 5.708097 l
|
||||
h
|
||||
13.115711 5.969321 m
|
||||
12.968349 6.420619 l
|
||||
12.798800 6.365256 12.674588 6.219535 12.646772 6.043359 c
|
||||
12.618958 5.867183 12.692234 5.690281 12.836478 5.585376 c
|
||||
13.115711 5.969321 l
|
||||
h
|
||||
13.834077 8.222376 m
|
||||
14.221668 8.496526 l
|
||||
14.206144 8.518474 14.188784 8.539063 14.169774 8.558073 c
|
||||
13.834077 8.222376 l
|
||||
h
|
||||
13.474895 8.581559 m
|
||||
13.369680 9.044500 l
|
||||
13.201114 9.006190 13.066693 8.879284 13.018762 8.713197 c
|
||||
12.970830 8.547110 13.016963 8.368095 13.139197 8.245862 c
|
||||
13.474895 8.581559 l
|
||||
h
|
||||
14.193260 10.377472 m
|
||||
14.619765 10.585986 l
|
||||
14.599768 10.626891 14.573989 10.664707 14.543221 10.698271 c
|
||||
14.193260 10.377472 l
|
||||
h
|
||||
8.381030 11.814203 m
|
||||
7.917068 11.914822 l
|
||||
7.884080 11.762714 7.927746 11.604099 8.033934 11.490305 c
|
||||
8.140121 11.376513 8.295343 11.321997 8.449365 11.344399 c
|
||||
8.381030 11.814203 l
|
||||
h
|
||||
8.642253 14.948887 m
|
||||
9.111748 15.019311 l
|
||||
8.642253 14.948887 l
|
||||
h
|
||||
6.291239 16.744801 m
|
||||
6.262227 17.218662 l
|
||||
6.224693 17.216364 6.187564 17.209614 6.151623 17.198555 c
|
||||
6.291239 16.744801 l
|
||||
h
|
||||
5.474915 16.026436 m
|
||||
5.948456 16.060261 l
|
||||
5.474915 16.026436 l
|
||||
h
|
||||
5.474915 11.291754 m
|
||||
5.030037 11.457493 l
|
||||
5.474915 11.291754 l
|
||||
h
|
||||
3.673396 9.803555 m
|
||||
1.355035 10.097433 l
|
||||
1.235632 9.155476 l
|
||||
3.553993 8.861599 l
|
||||
3.673396 9.803555 l
|
||||
h
|
||||
0.999601 9.997839 m
|
||||
-0.029049 9.178730 -0.454726 7.875908 -0.474048 6.619066 c
|
||||
-0.493367 5.362488 -0.110331 4.058727 0.595713 3.161463 c
|
||||
1.341894 3.748621 l
|
||||
0.794064 4.444821 0.458734 5.524729 0.475334 6.604470 c
|
||||
0.491930 7.683949 0.856455 8.670100 1.591066 9.255068 c
|
||||
0.999601 9.997839 l
|
||||
h
|
||||
0.565608 3.204407 m
|
||||
0.721970 2.952868 1.013515 2.611341 1.407507 2.372385 c
|
||||
1.811404 2.127421 2.357187 1.973489 2.959612 2.192553 c
|
||||
2.635129 3.084882 l
|
||||
2.375515 2.990478 2.132184 3.043347 1.899893 3.184233 c
|
||||
1.657696 3.331126 1.465977 3.554496 1.372000 3.705677 c
|
||||
0.565608 3.204407 l
|
||||
h
|
||||
2.959612 2.192553 m
|
||||
3.816493 2.504146 4.293336 2.639887 4.406158 2.665923 c
|
||||
4.192656 3.591103 l
|
||||
4.022485 3.551832 3.502325 3.400227 2.635129 3.084882 c
|
||||
2.959612 2.192553 l
|
||||
h
|
||||
4.167043 2.672591 m
|
||||
5.229115 2.364247 6.254152 2.163970 8.576947 2.163970 c
|
||||
8.576947 3.113465 l
|
||||
6.328326 3.113465 5.394184 3.305025 4.431771 3.584435 c
|
||||
4.167043 2.672591 l
|
||||
h
|
||||
8.458392 2.179011 m
|
||||
14.662457 0.579016 l
|
||||
14.899569 1.498427 l
|
||||
8.695503 3.098424 l
|
||||
8.458392 2.179011 l
|
||||
h
|
||||
14.781013 0.563974 m
|
||||
15.036198 0.563974 15.495326 0.684875 15.814721 1.047266 c
|
||||
16.180891 1.462728 16.264221 2.072176 15.934578 2.828420 c
|
||||
15.064179 2.449016 l
|
||||
15.289635 1.931793 15.160722 1.741243 15.102402 1.675073 c
|
||||
15.055794 1.622190 14.990156 1.579316 14.916806 1.549556 c
|
||||
14.881134 1.535082 14.847747 1.525430 14.820526 1.519657 c
|
||||
14.791491 1.513498 14.777695 1.513469 14.781013 1.513469 c
|
||||
14.781013 0.563974 l
|
||||
h
|
||||
15.651489 3.088437 m
|
||||
11.210685 4.590474 l
|
||||
10.906463 3.691035 l
|
||||
15.347267 2.188998 l
|
||||
15.651489 3.088437 l
|
||||
h
|
||||
10.988150 3.671260 m
|
||||
12.947328 3.377382 l
|
||||
13.088176 4.316372 l
|
||||
11.128998 4.610250 l
|
||||
10.988150 3.671260 l
|
||||
h
|
||||
12.782211 3.434681 m
|
||||
12.991495 3.315090 13.204453 3.370091 13.288217 3.396689 c
|
||||
13.400116 3.432221 13.506123 3.490767 13.598186 3.554502 c
|
||||
13.783985 3.683133 13.977411 3.877748 14.120350 4.119644 c
|
||||
14.264680 4.363894 14.369576 4.678114 14.335162 5.031647 c
|
||||
14.300108 5.391746 14.125634 5.739002 13.805044 6.049252 c
|
||||
13.144745 5.366943 l
|
||||
13.330275 5.187398 13.380290 5.040778 13.390134 4.939653 c
|
||||
13.400617 4.831963 13.370820 4.717613 13.302905 4.602680 c
|
||||
13.233600 4.485394 13.137231 4.390213 13.057724 4.335170 c
|
||||
13.017135 4.307070 12.996612 4.300308 13.000857 4.301657 c
|
||||
13.003194 4.302399 13.024761 4.309311 13.061064 4.310122 c
|
||||
13.095938 4.310902 13.170414 4.306433 13.253292 4.259073 c
|
||||
12.782211 3.434681 l
|
||||
h
|
||||
13.754128 6.092043 m
|
||||
13.394944 6.353267 l
|
||||
12.836478 5.585376 l
|
||||
13.195662 5.324152 l
|
||||
13.754128 6.092043 l
|
||||
h
|
||||
13.263074 5.518023 m
|
||||
13.593105 5.625790 14.123367 5.907292 14.433812 6.409482 c
|
||||
14.595931 6.671733 14.696482 6.993351 14.669847 7.364054 c
|
||||
14.643518 7.730516 14.495621 8.109214 14.221668 8.496526 c
|
||||
13.446486 7.948226 l
|
||||
13.646002 7.666152 13.711709 7.450294 13.722795 7.296009 c
|
||||
13.733575 7.145966 13.695351 7.020646 13.626177 6.908748 c
|
||||
13.474038 6.662641 13.171650 6.487002 12.968349 6.420619 c
|
||||
13.263074 5.518023 l
|
||||
h
|
||||
14.169774 8.558073 m
|
||||
13.810592 8.917255 l
|
||||
13.139197 8.245862 l
|
||||
13.498380 7.886679 l
|
||||
14.169774 8.558073 l
|
||||
h
|
||||
13.580109 8.118617 m
|
||||
13.896242 8.190466 14.344993 8.395787 14.624650 8.816864 c
|
||||
14.929440 9.275781 14.963785 9.882310 14.619765 10.585986 c
|
||||
13.766754 10.168959 l
|
||||
13.997427 9.697128 13.912044 9.460121 13.833706 9.342171 c
|
||||
13.730235 9.186377 13.532457 9.081495 13.369680 9.044500 c
|
||||
13.580109 8.118617 l
|
||||
h
|
||||
14.543221 10.698271 m
|
||||
13.820906 11.486253 12.989320 12.223852 11.896564 12.288132 c
|
||||
11.840808 11.340275 l
|
||||
12.524374 11.300065 13.128883 10.836036 13.843298 10.056674 c
|
||||
14.543221 10.698271 l
|
||||
h
|
||||
11.896564 12.288132 m
|
||||
11.441970 12.314873 10.711069 12.336796 10.019300 12.341186 c
|
||||
9.341933 12.345484 8.654247 12.333687 8.312695 12.284006 c
|
||||
8.449365 11.344399 l
|
||||
8.706450 11.381794 9.318512 11.396118 10.013274 11.391710 c
|
||||
10.693633 11.387392 11.407242 11.365778 11.840808 11.340275 c
|
||||
11.896564 12.288132 l
|
||||
h
|
||||
8.844993 11.713585 m
|
||||
8.948084 12.188952 9.040332 12.829445 9.094679 13.432834 c
|
||||
9.147870 14.023395 9.169946 14.631327 9.111748 15.019311 c
|
||||
8.172758 14.878462 l
|
||||
8.212520 14.613384 8.201942 14.105675 8.149012 13.518009 c
|
||||
8.097237 12.943172 8.009893 12.342852 7.917068 11.914822 c
|
||||
8.844993 11.713585 l
|
||||
h
|
||||
9.111748 15.019311 m
|
||||
8.944062 16.137217 7.805658 17.313158 6.262227 17.218662 c
|
||||
6.320251 16.270941 l
|
||||
7.336813 16.333179 8.072657 15.545805 8.172758 14.878462 c
|
||||
9.111748 15.019311 l
|
||||
h
|
||||
6.151623 17.198555 m
|
||||
5.976391 17.144638 5.715709 17.036982 5.490986 16.876261 c
|
||||
5.292936 16.734617 4.969444 16.439627 5.001374 15.992612 c
|
||||
5.948456 16.060261 l
|
||||
5.951383 16.019283 5.934667 15.999795 5.943361 16.012491 c
|
||||
5.954769 16.029152 5.984430 16.061831 6.043331 16.103956 c
|
||||
6.162553 16.189222 6.323094 16.257891 6.430855 16.291048 c
|
||||
6.151623 17.198555 l
|
||||
h
|
||||
5.001374 15.992612 m
|
||||
5.011176 15.855374 5.059216 15.566318 5.104405 15.255149 c
|
||||
5.152757 14.922197 5.207128 14.509316 5.241940 14.062993 c
|
||||
5.312967 13.152368 5.295928 12.171200 5.030037 11.457493 c
|
||||
5.919792 11.126015 l
|
||||
6.262142 12.044956 6.261431 13.202559 6.188560 14.136827 c
|
||||
6.151423 14.612950 6.093790 15.049047 6.044043 15.391605 c
|
||||
5.991133 15.755945 5.954979 15.968927 5.948456 16.060261 c
|
||||
5.001374 15.992612 l
|
||||
h
|
||||
5.030037 11.457493 m
|
||||
4.953650 11.252455 4.742510 10.903708 4.434547 10.555828 c
|
||||
4.127778 10.209298 3.769400 9.914337 3.428282 9.769621 c
|
||||
3.799107 8.895533 l
|
||||
4.320028 9.116529 4.788858 9.523607 5.145489 9.926461 c
|
||||
5.500926 10.327968 5.789377 10.775953 5.919792 11.126015 c
|
||||
5.030037 11.457493 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
7995
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 16.615845 16.660034 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000008085 00000 n
|
||||
0000008108 00000 n
|
||||
0000008281 00000 n
|
||||
0000008355 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
8414
|
||||
%%EOF
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "nostr-hello-outline-black.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "nostr-hello-outline-black@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "nostr-hello-outline-black@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 381 B |
Binary file not shown.
|
Before Width: | Height: | Size: 723 B |
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// NIP05Badge.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-01-11.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct NIP05Badge: View {
|
||||
let nip05: NIP05
|
||||
let pubkey: String
|
||||
let contacts: Contacts
|
||||
let show_domain: Bool
|
||||
let clickable: Bool
|
||||
|
||||
@Environment(\.openURL) var openURL
|
||||
|
||||
init (nip05: NIP05, pubkey: String, contacts: Contacts, show_domain: Bool, clickable: Bool) {
|
||||
self.nip05 = nip05
|
||||
self.pubkey = pubkey
|
||||
self.contacts = contacts
|
||||
self.show_domain = show_domain
|
||||
self.clickable = clickable
|
||||
}
|
||||
|
||||
var nip05_color: Color {
|
||||
return get_nip05_color(pubkey: pubkey, contacts: contacts)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 2) {
|
||||
Image(systemName: "checkmark.seal.fill")
|
||||
.font(.footnote)
|
||||
.foregroundColor(nip05_color)
|
||||
if show_domain {
|
||||
if clickable {
|
||||
Text(nip05.host)
|
||||
.foregroundColor(nip05_color)
|
||||
.onTapGesture {
|
||||
if let nip5url = nip05.siteUrl {
|
||||
openURL(nip5url)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Text(nip05.host)
|
||||
.foregroundColor(nip05_color)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func get_nip05_color(pubkey: String, contacts: Contacts) -> Color {
|
||||
return contacts.is_friend_or_self(pubkey) ? .accentColor : .gray
|
||||
}
|
||||
|
||||
struct NIP05Badge_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let test_state = test_damus_state()
|
||||
NIP05Badge(nip05: NIP05(username: "jb55", host: "jb55.com"), pubkey: test_state.pubkey, contacts: test_state.contacts, show_domain: true, clickable: false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// Reposted.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-01-11.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct Reposted: View {
|
||||
let damus: DamusState
|
||||
let pubkey: String
|
||||
let profile: Profile?
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .center) {
|
||||
Image(systemName: "arrow.2.squarepath")
|
||||
.font(.footnote)
|
||||
.foregroundColor(Color.gray)
|
||||
ProfileName(pubkey: pubkey, profile: profile, damus: damus, show_friend_confirmed: true, show_nip5_domain: false)
|
||||
.foregroundColor(Color.gray)
|
||||
Text("Reposted", comment: "Text indicating that the post was reposted (i.e. re-shared).")
|
||||
.font(.footnote)
|
||||
.foregroundColor(Color.gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Reposted_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let test_state = test_damus_state()
|
||||
Reposted(damus: test_state, pubkey: test_state.pubkey, profile: make_test_profile())
|
||||
}
|
||||
}
|
||||
+12
-12
@@ -172,13 +172,20 @@ struct ContentView: View {
|
||||
.navigationBarTitle(selected_timeline == .home ? NSLocalizedString("Home", comment: "Navigation bar title for Home view where posts and replies appear from those who the user is following.") : NSLocalizedString("Global", comment: "Navigation bar title for Global view where posts from all connected relay servers appear."), displayMode: .inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .principal) {
|
||||
if selected_timeline == .home {
|
||||
switch selected_timeline {
|
||||
case .home:
|
||||
Image("damus-home")
|
||||
.resizable()
|
||||
.frame(width:30,height:30)
|
||||
.shadow(color: Color("DamusPurple"), radius: 2)
|
||||
} else {
|
||||
Text("Global")
|
||||
case .dms:
|
||||
Text("DM", comment: "Toolbar label for DM view, which is the English abbreviation for Direct Message.")
|
||||
case .notifications:
|
||||
Text("Notifications", comment: "Toolbar label for Notifications view.")
|
||||
case .search:
|
||||
Text("Global", comment: "Toolbar label for Global view where posts from all connected relay servers appear.")
|
||||
case .none:
|
||||
Text("", comment: "Toolbar label for unknown views. This label would be displayed only if a new timeline view is added but a toolbar label was not explicitly assigned to it yet.")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +223,7 @@ struct ContentView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
if let damus = self.damus_state {
|
||||
@@ -229,14 +236,7 @@ struct ContentView: View {
|
||||
Button {
|
||||
isSideBarOpened.toggle()
|
||||
} label: {
|
||||
let profile_model = ProfileModel(pubkey: damus_state!.pubkey, damus: damus_state!)
|
||||
let followers_model = FollowersModel(damus_state: damus_state!, target: damus_state!.pubkey)
|
||||
|
||||
if let picture = damus_state?.profiles.lookup(id: pubkey)?.picture {
|
||||
ProfilePicView(pubkey: damus_state!.pubkey, size: 32, highlight: .none, profiles: damus_state!.profiles, picture: picture)
|
||||
} else {
|
||||
Image(systemName: "person.fill")
|
||||
}
|
||||
ProfilePicView(pubkey: damus_state!.pubkey, size: 32, highlight: .none, profiles: damus_state!.profiles)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||
<string>"Granting Damus access to your photo library allows you to save photos.</string>
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>river</string>
|
||||
|
||||
@@ -16,6 +16,10 @@ class ActionBarModel: ObservableObject {
|
||||
@Published var boosts: Int
|
||||
@Published var tips: Int64
|
||||
|
||||
static func empty() -> ActionBarModel {
|
||||
return ActionBarModel(likes: 0, boosts: 0, tips: 0, our_like: nil, our_boost: nil, our_tip: nil)
|
||||
}
|
||||
|
||||
init(likes: Int, boosts: Int, tips: Int64, our_like: NostrEvent?, our_boost: NostrEvent?, our_tip: NostrEvent?) {
|
||||
self.likes = likes
|
||||
self.boosts = boosts
|
||||
@@ -25,6 +29,10 @@ class ActionBarModel: ObservableObject {
|
||||
self.our_tip = our_tip
|
||||
}
|
||||
|
||||
var is_empty: Bool {
|
||||
return likes == 0 && boosts == 0 && tips == 0
|
||||
}
|
||||
|
||||
var tipped: Bool {
|
||||
return our_tip != nil
|
||||
}
|
||||
|
||||
@@ -18,11 +18,11 @@ class FollowersModel: ObservableObject {
|
||||
let sub_id: String = UUID().description
|
||||
let profiles_id: String = UUID().description
|
||||
|
||||
var count_display: String {
|
||||
var count: Int? {
|
||||
guard let contacts = self.contacts else {
|
||||
return "?"
|
||||
return nil
|
||||
}
|
||||
return "\(contacts.count)";
|
||||
return contacts.count
|
||||
}
|
||||
|
||||
init(damus_state: DamusState, target: String) {
|
||||
@@ -73,31 +73,30 @@ class FollowersModel: ObservableObject {
|
||||
}
|
||||
|
||||
func handle_event(relay_id: String, ev: NostrConnectionEvent) {
|
||||
switch ev {
|
||||
case .ws_event:
|
||||
break
|
||||
case .nostr_event(let nev):
|
||||
switch nev {
|
||||
case .event(let sub_id, let ev):
|
||||
guard sub_id == self.sub_id || sub_id == self.profiles_id else {
|
||||
return
|
||||
}
|
||||
|
||||
if ev.known_kind == .contacts {
|
||||
handle_contact_event(ev)
|
||||
} else if ev.known_kind == .metadata {
|
||||
process_metadata_event(profiles: damus_state.profiles, ev: ev)
|
||||
}
|
||||
|
||||
case .notice(let msg):
|
||||
print("followingmodel notice: \(msg)")
|
||||
|
||||
case .eose(let sub_id):
|
||||
if sub_id == self.sub_id {
|
||||
load_profiles(relay_id: relay_id)
|
||||
} else if sub_id == self.profiles_id {
|
||||
damus_state.pool.unsubscribe(sub_id: profiles_id, to: [relay_id])
|
||||
}
|
||||
guard case .nostr_event(let nev) = ev else {
|
||||
return
|
||||
}
|
||||
|
||||
switch nev {
|
||||
case .event(let sub_id, let ev):
|
||||
guard sub_id == self.sub_id || sub_id == self.profiles_id else {
|
||||
return
|
||||
}
|
||||
|
||||
if ev.known_kind == .contacts {
|
||||
handle_contact_event(ev)
|
||||
} else if ev.known_kind == .metadata {
|
||||
process_metadata_event(profiles: damus_state.profiles, ev: ev)
|
||||
}
|
||||
|
||||
case .notice(let msg):
|
||||
print("followingmodel notice: \(msg)")
|
||||
|
||||
case .eose(let sub_id):
|
||||
if sub_id == self.sub_id {
|
||||
load_profiles(relay_id: relay_id)
|
||||
} else if sub_id == self.profiles_id {
|
||||
damus_state.pool.unsubscribe(sub_id: profiles_id, to: [relay_id])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,24 +347,23 @@ class HomeModel: ObservableObject {
|
||||
return m[kind]
|
||||
}
|
||||
|
||||
func handle_last_event(ev: NostrEvent, timeline: Timeline, shouldNotify: Bool = true) {
|
||||
let last_ev = get_last_event(timeline)
|
||||
|
||||
if last_ev == nil || last_ev!.created_at < ev.created_at {
|
||||
save_last_event(ev, timeline: timeline)
|
||||
if shouldNotify {
|
||||
new_events = NewEventsBits(prev: new_events, setting: timeline)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handle_notification(ev: NostrEvent) {
|
||||
guard event_has_our_pubkey(ev, our_pubkey: self.damus_state.pubkey) else {
|
||||
return
|
||||
}
|
||||
|
||||
if !insert_uniq_sorted_event(events: ¬ifications, new_ev: ev, cmp: { $0.created_at > $1.created_at }) {
|
||||
return
|
||||
}
|
||||
|
||||
handle_last_event(ev: ev, timeline: .notifications)
|
||||
}
|
||||
|
||||
func handle_last_event(ev: NostrEvent, timeline: Timeline, shouldNotify: Bool = true) {
|
||||
if let new_bits = handle_last_events(new_events: self.new_events, ev: ev, timeline: timeline, shouldNotify: shouldNotify) {
|
||||
new_events = new_bits
|
||||
}
|
||||
}
|
||||
|
||||
func insert_home_event(_ ev: NostrEvent) -> Bool {
|
||||
let ok = insert_uniq_sorted_event(events: &self.events, new_ev: ev, cmp: { $0.created_at > $1.created_at })
|
||||
@@ -391,49 +390,8 @@ class HomeModel: ObservableObject {
|
||||
}
|
||||
|
||||
func handle_dm(_ ev: NostrEvent) {
|
||||
|
||||
var inserted = false
|
||||
var found = false
|
||||
let ours = ev.pubkey == self.damus_state.pubkey
|
||||
var i = 0
|
||||
|
||||
var the_pk = ev.pubkey
|
||||
if ours {
|
||||
if let ref_pk = ev.referenced_pubkeys.first {
|
||||
the_pk = ref_pk.ref_id
|
||||
} else {
|
||||
// self dm!?
|
||||
print("TODO: handle self dm?")
|
||||
}
|
||||
}
|
||||
|
||||
for (pk, _) in dms.dms {
|
||||
if pk == the_pk {
|
||||
found = true
|
||||
inserted = insert_uniq_sorted_event(events: &(dms.dms[i].1.events), new_ev: ev) {
|
||||
$0.created_at < $1.created_at
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
|
||||
if !found {
|
||||
inserted = true
|
||||
let model = DirectMessageModel(events: [ev])
|
||||
dms.dms.append((the_pk, model))
|
||||
}
|
||||
|
||||
if inserted {
|
||||
handle_last_event(ev: ev, timeline: .dms, shouldNotify: !ours)
|
||||
|
||||
dms.dms = dms.dms.sorted { a, b in
|
||||
if a.1.events.count > 0 && b.1.events.count > 0 {
|
||||
return a.1.events.last!.created_at > b.1.events.last!.created_at
|
||||
}
|
||||
return false
|
||||
}
|
||||
if let notifs = handle_incoming_dm(prev_events: self.new_events, dms: self.dms, our_pubkey: self.damus_state.pubkey, ev: ev) {
|
||||
self.new_events = notifs
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -578,6 +536,13 @@ func process_metadata_event(profiles: Profiles, ev: NostrEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
let banner = tprof.profile.banner ?? ""
|
||||
if let _ = URL(string: banner) {
|
||||
DispatchQueue.main.async {
|
||||
notify(.profile_updated, ProfileUpdate(pubkey: ev.pubkey, profile: profile))
|
||||
}
|
||||
}
|
||||
|
||||
notify(.profile_updated, ProfileUpdate(pubkey: ev.pubkey, profile: profile))
|
||||
}
|
||||
|
||||
@@ -649,4 +614,75 @@ func load_our_relays(contacts: Contacts, our_pubkey: String, pool: RelayPool, m_
|
||||
}
|
||||
}
|
||||
|
||||
func handle_incoming_dm(prev_events: NewEventsBits, dms: DirectMessagesModel, our_pubkey: String, ev: NostrEvent) -> NewEventsBits? {
|
||||
var inserted = false
|
||||
var found = false
|
||||
let ours = ev.pubkey == our_pubkey
|
||||
var i = 0
|
||||
|
||||
var the_pk = ev.pubkey
|
||||
if ours {
|
||||
if let ref_pk = ev.referenced_pubkeys.first {
|
||||
the_pk = ref_pk.ref_id
|
||||
} else {
|
||||
// self dm!?
|
||||
print("TODO: handle self dm?")
|
||||
}
|
||||
}
|
||||
|
||||
for (pk, _) in dms.dms {
|
||||
if pk == the_pk {
|
||||
found = true
|
||||
inserted = insert_uniq_sorted_event(events: &(dms.dms[i].1.events), new_ev: ev) {
|
||||
$0.created_at < $1.created_at
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
|
||||
if !found {
|
||||
inserted = true
|
||||
let model = DirectMessageModel(events: [ev])
|
||||
dms.dms.append((the_pk, model))
|
||||
}
|
||||
|
||||
var new_events: NewEventsBits? = nil
|
||||
if inserted {
|
||||
new_events = handle_last_events(new_events: prev_events, ev: ev, timeline: .dms, shouldNotify: !ours)
|
||||
|
||||
dms.dms = dms.dms.filter({ $0.1.events.count > 0 }).sorted { a, b in
|
||||
return a.1.events.last!.created_at > b.1.events.last!.created_at
|
||||
}
|
||||
}
|
||||
|
||||
return new_events
|
||||
}
|
||||
|
||||
|
||||
/// A helper to determine if we need to notify the user of new events
|
||||
func handle_last_events(new_events: NewEventsBits, ev: NostrEvent, timeline: Timeline, shouldNotify: Bool = true) -> NewEventsBits? {
|
||||
let last_ev = get_last_event(timeline)
|
||||
|
||||
if last_ev == nil || last_ev!.created_at < ev.created_at {
|
||||
save_last_event(ev, timeline: timeline)
|
||||
if shouldNotify {
|
||||
return NewEventsBits(prev: new_events, setting: timeline)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
/// Sometimes we get garbage in our notifications. Ensure we have our pubkey on this event
|
||||
func event_has_our_pubkey(_ ev: NostrEvent, our_pubkey: String) -> Bool {
|
||||
for tag in ev.tags {
|
||||
if tag.count >= 2 && tag[0] == "p" && tag[1] == our_pubkey {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
//
|
||||
// KFImageModel.swift
|
||||
// damus
|
||||
//
|
||||
// Created by Oleg Abalonski on 1/11/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Kingfisher
|
||||
import SVGKit
|
||||
|
||||
class KFImageModel: ObservableObject {
|
||||
|
||||
let url: URL?
|
||||
let fallbackUrl: URL?
|
||||
let processor: ImageProcessor
|
||||
let serializer: CacheSerializer
|
||||
|
||||
@Published var refreshID = ""
|
||||
|
||||
init(url: URL?, fallbackUrl: URL?, maxByteSize: Int, downsampleSize: CGSize) {
|
||||
self.url = url
|
||||
self.fallbackUrl = fallbackUrl
|
||||
self.processor = CustomImageProcessor(maxSize: maxByteSize, downsampleSize: downsampleSize)
|
||||
self.serializer = CustomCacheSerializer(maxSize: maxByteSize, downsampleSize: downsampleSize)
|
||||
}
|
||||
|
||||
func refresh() -> Void {
|
||||
DispatchQueue.main.async {
|
||||
self.refreshID = UUID().uuidString
|
||||
}
|
||||
}
|
||||
|
||||
func cache(_ image: UIImage, forKey key: String) -> Void {
|
||||
KingfisherManager.shared.cache.store(image, forKey: key, processorIdentifier: processor.identifier) { _ in
|
||||
self.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
func downloadFailed() -> Void {
|
||||
guard let url = url, let fallbackUrl = fallbackUrl else { return }
|
||||
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
KingfisherManager.shared.downloader.downloadImage(with: fallbackUrl) { result in
|
||||
|
||||
var fallbackImage: UIImage {
|
||||
switch result {
|
||||
case .success(let imageLoadingResult):
|
||||
return imageLoadingResult.image
|
||||
case .failure(let error):
|
||||
print(error)
|
||||
return UIImage()
|
||||
}
|
||||
}
|
||||
|
||||
self.cache(fallbackImage, forKey: url.absoluteString)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CustomImageProcessor: ImageProcessor {
|
||||
|
||||
let maxSize: Int
|
||||
let downsampleSize: CGSize
|
||||
|
||||
let identifier = "com.damus.customimageprocessor"
|
||||
|
||||
func process(item: ImageProcessItem, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? {
|
||||
|
||||
switch item {
|
||||
case .image(_):
|
||||
// This case will never run
|
||||
return DefaultImageProcessor.default.process(item: item, options: options)
|
||||
case .data(let data):
|
||||
|
||||
// Handle large image size
|
||||
if data.count > maxSize {
|
||||
return KingfisherWrapper.downsampledImage(data: data, to: downsampleSize, scale: options.scaleFactor)
|
||||
}
|
||||
|
||||
// Handle SVG image
|
||||
if let svgImage = SVGKImage(data: data), let image = svgImage.uiImage {
|
||||
return image.kf.scaled(to: options.scaleFactor)
|
||||
}
|
||||
|
||||
return DefaultImageProcessor.default.process(item: item, options: options)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CustomCacheSerializer: CacheSerializer {
|
||||
|
||||
let maxSize: Int
|
||||
let downsampleSize: CGSize
|
||||
|
||||
func data(with image: Kingfisher.KFCrossPlatformImage, original: Data?) -> Data? {
|
||||
return DefaultCacheSerializer.default.data(with: image, original: original)
|
||||
}
|
||||
|
||||
func image(with data: Data, options: Kingfisher.KingfisherParsedOptionsInfo) -> Kingfisher.KFCrossPlatformImage? {
|
||||
if data.count > maxSize {
|
||||
return KingfisherWrapper.downsampledImage(data: data, to: downsampleSize, scale: options.scaleFactor)
|
||||
}
|
||||
|
||||
return DefaultCacheSerializer.default.image(with: data, options: options)
|
||||
}
|
||||
}
|
||||
@@ -198,11 +198,7 @@ enum Amount: Equatable {
|
||||
let sats = NSNumber(value: (Double(amt) / 1000.0))
|
||||
let formattedSats = numberFormatter.string(from: sats) ?? sats.stringValue
|
||||
|
||||
if formattedSats == numberFormatter.string(from: 1) {
|
||||
return NSLocalizedString("\(formattedSats) sat", comment: "Amount of 1 sat.")
|
||||
}
|
||||
|
||||
return NSLocalizedString("\(formattedSats) sats", comment: "Amount of sats.")
|
||||
return String(format: NSLocalizedString("sats_count", comment: "Amount of sats."), sats.decimalValue as NSDecimalNumber, formattedSats)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// LikesModel.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-01-11.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
class ReactionsModel: ObservableObject {
|
||||
let state: DamusState
|
||||
let target: String
|
||||
let sub_id: String
|
||||
let profiles_id: String
|
||||
|
||||
@Published var reactions: [NostrEvent]
|
||||
|
||||
init (state: DamusState, target: String) {
|
||||
self.state = state
|
||||
self.target = target
|
||||
self.sub_id = UUID().description
|
||||
self.profiles_id = UUID().description
|
||||
self.reactions = []
|
||||
}
|
||||
|
||||
func get_filter() -> NostrFilter {
|
||||
var filter = NostrFilter.filter_kinds([7])
|
||||
filter.referenced_ids = [target]
|
||||
filter.limit = 500
|
||||
return filter
|
||||
}
|
||||
|
||||
func subscribe() {
|
||||
let filter = get_filter()
|
||||
let filters = [filter]
|
||||
self.state.pool.subscribe(sub_id: sub_id, filters: filters, handler: handle_nostr_event)
|
||||
}
|
||||
|
||||
func unsubscribe() {
|
||||
self.state.pool.unsubscribe(sub_id: sub_id)
|
||||
}
|
||||
|
||||
func handle_event(relay_id: String, ev: NostrEvent) {
|
||||
guard ev.kind == 7 else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let reacted_to = last_etag(tags: ev.tags) else {
|
||||
return
|
||||
}
|
||||
|
||||
guard reacted_to == self.target else {
|
||||
return
|
||||
}
|
||||
|
||||
if insert_uniq_sorted_event(events: &self.reactions, new_ev: ev, cmp: { a, b in a.created_at < b.created_at } ) {
|
||||
objectWillChange.send()
|
||||
}
|
||||
}
|
||||
|
||||
func handle_nostr_event(relay_id: String, ev: NostrConnectionEvent) {
|
||||
guard case .nostr_event(let nev) = ev else {
|
||||
return
|
||||
}
|
||||
|
||||
switch nev {
|
||||
case .event(_, let ev):
|
||||
handle_event(relay_id: relay_id, ev: ev)
|
||||
|
||||
case .notice(_):
|
||||
break
|
||||
case .eose(_):
|
||||
load_profiles(profiles_subid: profiles_id, relay_id: relay_id, events: reactions, damus_state: state)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-20
@@ -10,12 +10,13 @@ import Foundation
|
||||
struct Profile: Codable {
|
||||
var value: [String: String]
|
||||
|
||||
init (name: String?, display_name: String?, about: String?, picture: String?, website: String?, lud06: String?, lud16: String?, nip05: String?) {
|
||||
init (name: String?, display_name: String?, about: String?, picture: String?, banner: String?, website: String?, lud06: String?, lud16: String?, nip05: String?) {
|
||||
self.value = [:]
|
||||
self.name = name
|
||||
self.display_name = display_name
|
||||
self.about = about
|
||||
self.picture = picture
|
||||
self.banner = banner
|
||||
self.website = website
|
||||
self.lud06 = lud06
|
||||
self.lud16 = lud16
|
||||
@@ -42,6 +43,11 @@ struct Profile: Codable {
|
||||
set(s) { value["picture"] = s }
|
||||
}
|
||||
|
||||
var banner: String? {
|
||||
get { return value["banner"]; }
|
||||
set(s) { value["banner"] = s }
|
||||
}
|
||||
|
||||
var website: String? {
|
||||
get { return value["website"]; }
|
||||
set(s) { value["website"] = s }
|
||||
@@ -94,26 +100,9 @@ struct Profile: Codable {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
struct Profile: Decodable {
|
||||
let name: String?
|
||||
let display_name: String?
|
||||
let about: String?
|
||||
let picture: String?
|
||||
let website: String?
|
||||
let nip05: String?
|
||||
let lud06: String?
|
||||
let lud16: String?
|
||||
|
||||
var lightning_uri: URL? {
|
||||
return make_ln_url(self.lud06) ?? make_ln_url(self.lud16)
|
||||
}
|
||||
|
||||
static func displayName(profile: Profile?, pubkey: String) -> String {
|
||||
return profile?.name ?? abbrev_pubkey(pubkey)
|
||||
}
|
||||
func make_test_profile() -> Profile {
|
||||
return Profile(name: "jb55", display_name: "Will", about: "Its a me", picture: "https://cdn.jb55.com/img/red-me.jpg", banner: "https://pbs.twimg.com/profile_banners/9918032/1531711830/600x200", website: "jb55.com", lud06: "jb55@jb55.com", lud16: nil, nip05: "jb55@jb55.com")
|
||||
}
|
||||
*/
|
||||
|
||||
func make_ln_url(_ str: String?) -> URL? {
|
||||
return str.flatMap { URL(string: "lightning:" + $0) }
|
||||
|
||||
@@ -772,6 +772,15 @@ func validate_event(ev: NostrEvent) -> ValidationResult {
|
||||
return ok ? .ok : .bad_sig
|
||||
}
|
||||
|
||||
func last_etag(tags: [[String]]) -> String? {
|
||||
var e: String? = nil
|
||||
for tag in tags {
|
||||
if tag.count >= 2 && tag[0] == "e" {
|
||||
e = tag[1]
|
||||
}
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func inner_event_or_self(ev: NostrEvent) -> NostrEvent {
|
||||
guard let inner_ev = ev.inner_event else {
|
||||
|
||||
@@ -15,10 +15,11 @@ struct NostrMetadata: Codable {
|
||||
let website: String?
|
||||
let nip05: String?
|
||||
let picture: String?
|
||||
let banner: String?
|
||||
let lud06: String?
|
||||
let lud16: String?
|
||||
}
|
||||
|
||||
func create_account_to_metadata(_ model: CreateAccountModel) -> NostrMetadata {
|
||||
return NostrMetadata(display_name: model.real_name, name: model.nick_name, about: model.about, website: nil, nip05: nil, picture: nil, lud06: nil, lud16: nil)
|
||||
return NostrMetadata(display_name: model.real_name, name: model.nick_name, about: model.about, website: nil, nip05: nil, picture: nil, banner: nil, lud06: nil, lud16: nil)
|
||||
}
|
||||
|
||||
@@ -29,14 +29,6 @@ struct EventActionBar: View {
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
/*
|
||||
EventActionButton(img: "square.and.arrow.up") {
|
||||
print("share")
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
*/
|
||||
if damus_state.keypair.privkey != nil {
|
||||
EventActionButton(img: "bubble.left", col: nil) {
|
||||
notify(.reply, event)
|
||||
@@ -45,9 +37,6 @@ struct EventActionBar: View {
|
||||
}
|
||||
|
||||
HStack(alignment: .bottom) {
|
||||
Text("\(bar.boosts > 0 ? "\(bar.boosts)" : "")")
|
||||
.font(.footnote.weight(.medium))
|
||||
.foregroundColor(bar.boosted ? Color.green : Color.gray)
|
||||
|
||||
EventActionButton(img: "arrow.2.squarepath", col: bar.boosted ? Color.green : nil) {
|
||||
if bar.boosted {
|
||||
@@ -55,21 +44,27 @@ struct EventActionBar: View {
|
||||
} else {
|
||||
self.confirm_boost = true
|
||||
}
|
||||
}.overlay {
|
||||
Text("\(bar.boosts > 0 ? "\(bar.boosts)" : "")")
|
||||
.offset(x: 22)
|
||||
.font(.footnote.weight(.medium))
|
||||
.foregroundColor(bar.boosted ? Color.green : Color.gray)
|
||||
}
|
||||
}
|
||||
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
HStack(alignment: .bottom) {
|
||||
Text("\(bar.likes > 0 ? "\(bar.likes)" : "")")
|
||||
.font(.footnote.weight(.medium))
|
||||
.foregroundColor(bar.liked ? Color.orange : Color.gray)
|
||||
|
||||
LikeButton(liked: bar.liked) {
|
||||
if bar.liked {
|
||||
notify(.delete, bar.our_like)
|
||||
} else {
|
||||
send_like()
|
||||
}
|
||||
}.overlay {
|
||||
Text("\(bar.likes > 0 ? "\(bar.likes)" : "")")
|
||||
.offset(x: 22)
|
||||
.font(.footnote.weight(.medium))
|
||||
.foregroundColor(bar.liked ? Color.accentColor : Color.gray)
|
||||
}
|
||||
}
|
||||
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
|
||||
@@ -102,15 +97,15 @@ struct EventActionBar: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.alert(NSLocalizedString("Boost", comment: "Title of alert for confirming to boost a post."), isPresented: $confirm_boost) {
|
||||
Button("Cancel") {
|
||||
.alert(NSLocalizedString("Repost", comment: "Title of alert for confirming to repost a post."), isPresented: $confirm_boost) {
|
||||
Button(NSLocalizedString("Cancel", comment: "Button to cancel out of reposting a post.")) {
|
||||
confirm_boost = false
|
||||
}
|
||||
Button(NSLocalizedString("Boost", comment: "Button to confirm boosting a post.")) {
|
||||
Button(NSLocalizedString("Repost", comment: "Button to confirm reposting a post.")) {
|
||||
send_boost()
|
||||
}
|
||||
} message: {
|
||||
Text("Are you sure you want to boost this post?", comment: "Alert message to ask if user wants to boost a post.")
|
||||
Text("Are you sure you want to repost this?", comment: "Alert message to ask if user wants to repost a post.")
|
||||
}
|
||||
.onReceive(handle_notify(.liked)) { n in
|
||||
let liked = n.object as! Counted
|
||||
@@ -154,7 +149,7 @@ struct EventActionBar: View {
|
||||
|
||||
func EventActionButton(img: String, col: Color?, action: @escaping () -> ()) -> some View {
|
||||
Button(action: action) {
|
||||
Label(" ", systemImage: img)
|
||||
Label(NSLocalizedString("\u{00A0}", comment: "Non-breaking space character to fill in blank space next to event action button icons."), systemImage: img)
|
||||
.font(.footnote.weight(.medium))
|
||||
.foregroundColor(col == nil ? Color.gray : col!)
|
||||
}
|
||||
@@ -168,13 +163,8 @@ struct LikeButton: View {
|
||||
|
||||
var body: some View {
|
||||
Button(action: action) {
|
||||
if liked {
|
||||
Text("🤙", comment: "Button with emoji to like an event.")
|
||||
} else {
|
||||
Image("shaka")
|
||||
.renderingMode(.template)
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
Image(liked ? "shaka-full" : "shaka-line")
|
||||
.foregroundColor(liked ? .accentColor : .gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,8 +174,19 @@ struct EventActionBar_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let pk = "pubkey"
|
||||
let ds = test_damus_state()
|
||||
let bar = ActionBarModel(likes: 0, boosts: 0, tips: 0, our_like: nil, our_boost: nil, our_tip: nil)
|
||||
let ev = NostrEvent(content: "hi", pubkey: pk)
|
||||
EventActionBar(damus_state: ds, event: ev, bar: bar)
|
||||
|
||||
let bar = ActionBarModel(likes: 0, boosts: 0, tips: 0, our_like: nil, our_boost: nil, our_tip: nil)
|
||||
let likedbar = ActionBarModel(likes: 10, boosts: 0, tips: 0, our_like: nil, our_boost: nil, our_tip: nil)
|
||||
let likedbar_ours = ActionBarModel(likes: 10, boosts: 0, tips: 0, our_like: NostrEvent(id: "", content: "", pubkey: ""), our_boost: nil, our_tip: nil)
|
||||
|
||||
VStack(spacing: 50) {
|
||||
EventActionBar(damus_state: ds, event: ev, bar: bar)
|
||||
|
||||
EventActionBar(damus_state: ds, event: ev, bar: likedbar)
|
||||
|
||||
EventActionBar(damus_state: ds, event: ev, bar: likedbar_ours)
|
||||
}
|
||||
.padding(20)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// EventDetailBar.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-01-08.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct EventDetailBar: View {
|
||||
let state: DamusState
|
||||
let target: String
|
||||
@StateObject var bar: ActionBarModel
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
if bar.boosts > 0 {
|
||||
Text("\(Text("\(bar.boosts)", comment: "Number of reposts.").font(.body.bold())) \(Text(String(format: NSLocalizedString("reposts_count", comment: "Part of a larger sentence to describe how many reposts there are."), bar.boosts)).foregroundColor(.gray))", comment: "Sentence composed of 2 variables to describe how many reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.")
|
||||
}
|
||||
|
||||
if bar.likes > 0 {
|
||||
NavigationLink(destination: ReactionsView(damus_state: state, model: ReactionsModel(state: state, target: target))) {
|
||||
Text("\(Text("\(bar.likes)", comment: "Number of reactions on a post.").font(.body.bold())) \(Text(String(format: NSLocalizedString("reactions_count", comment: "Part of a larger sentence to describe how many reactions there are on a post."), bar.likes)).foregroundColor(.gray))", comment: "Sentence composed of 2 variables to describe how many reactions there are on a post. In source English, the first variable is the number of reactions, and the second variable is 'Reaction' or 'Reactions'.")
|
||||
}
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
}
|
||||
|
||||
if bar.tips > 0 {
|
||||
Text("\(Text("\(bar.tips)", comment: "Number of tip payments on a post.").font(.body.bold())) \(Text(String(format: NSLocalizedString("tips_count", comment: "Part of a larger sentence to describe how many tip payments there are on a post."), bar.boosts)).foregroundColor(.gray))", comment: "Sentence composed of 2 variables to describe how many tip payments there are on a post. In source English, the first variable is the number of tip payments, and the second variable is 'Tip' or 'Tips'.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct EventDetailBar_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
EventDetailBar(state: test_damus_state(), target: "", bar: ActionBarModel.empty())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
//
|
||||
// BannerImageView.swift
|
||||
// damus
|
||||
//
|
||||
// Created by Jason Jōb on 2023-01-10.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Kingfisher
|
||||
|
||||
struct InnerBannerImageView: View {
|
||||
|
||||
let defaultImage = UIImage(named: "profile-banner") ?? UIImage()
|
||||
|
||||
@ObservedObject var imageModel: KFImageModel
|
||||
|
||||
init(url: URL?) {
|
||||
self.imageModel = KFImageModel(
|
||||
url: url,
|
||||
fallbackUrl: nil,
|
||||
maxByteSize: 5000000,
|
||||
downsampleSize: CGSize(width: 750, height: 250)
|
||||
)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
Color(uiColor: .systemBackground)
|
||||
|
||||
if (imageModel.url != nil) {
|
||||
KFAnimatedImage(imageModel.url)
|
||||
.callbackQueue(.dispatch(.global(qos: .background)))
|
||||
.processingQueue(.dispatch(.global(qos: .background)))
|
||||
.serialize(by: imageModel.serializer)
|
||||
.setProcessor(imageModel.processor)
|
||||
.configure { view in
|
||||
view.framePreloadCount = 1
|
||||
}
|
||||
.placeholder { _ in
|
||||
Color(uiColor: .secondarySystemBackground)
|
||||
}
|
||||
.scaleFactor(UIScreen.main.scale)
|
||||
.loadDiskFileSynchronously()
|
||||
.fade(duration: 0.1)
|
||||
.onFailureImage(defaultImage)
|
||||
.id(imageModel.refreshID)
|
||||
} else {
|
||||
Image(uiImage: defaultImage).resizable()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct BannerImageView: View {
|
||||
let pubkey: String
|
||||
let profiles: Profiles
|
||||
|
||||
@State var banner: String?
|
||||
|
||||
init (pubkey: String, profiles: Profiles, banner: String? = nil) {
|
||||
self.pubkey = pubkey
|
||||
self.profiles = profiles
|
||||
self._banner = State(initialValue: banner)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
InnerBannerImageView(url: get_banner_url(banner: banner, pubkey: pubkey, profiles: profiles))
|
||||
.onReceive(handle_notify(.profile_updated)) { notif in
|
||||
let updated = notif.object as! ProfileUpdate
|
||||
|
||||
guard updated.pubkey == self.pubkey else {
|
||||
return
|
||||
}
|
||||
|
||||
if let bannerImage = updated.profile.banner {
|
||||
self.banner = bannerImage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func get_banner_url(banner: String?, pubkey: String, profiles: Profiles) -> URL? {
|
||||
let bannerUrlString = banner ?? profiles.lookup(id: pubkey)?.banner ?? ""
|
||||
if let url = URL(string: bannerUrlString) {
|
||||
return url
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
struct BannerImageView_Previews: PreviewProvider {
|
||||
static let pubkey = "ca48854ac6555fed8e439ebb4fa2d928410e0eef13fa41164ec45aaaa132d846"
|
||||
|
||||
static var previews: some View {
|
||||
BannerImageView(
|
||||
pubkey: pubkey,
|
||||
profiles: make_preview_profiles(pubkey))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ struct ConfigView: View {
|
||||
Button(NSLocalizedString("Cancel", comment: "Cancel out of logging out the user.")) {
|
||||
confirm_logout = false
|
||||
}
|
||||
Button(NSLocalizedString("Logout", comment: "Button for logging out the user.")) {
|
||||
Button(NSLocalizedString("Logout", comment: "Button for logging out the user.")) {
|
||||
notify(.logout, ())
|
||||
}
|
||||
} message: {
|
||||
|
||||
@@ -166,7 +166,7 @@ struct DMChatView_Previews: PreviewProvider {
|
||||
}
|
||||
|
||||
|
||||
func create_dm(_ message: String, to_pk: String, tags: [[String]], keypair: Keypair) -> NostrEvent?
|
||||
func create_dm(_ message: String, to_pk: String, tags: [[String]], keypair: Keypair, created_at: Int64? = nil) -> NostrEvent?
|
||||
{
|
||||
guard let privkey = keypair.privkey else {
|
||||
return nil
|
||||
@@ -181,7 +181,9 @@ func create_dm(_ message: String, to_pk: String, tags: [[String]], keypair: Keyp
|
||||
return nil
|
||||
}
|
||||
let enc_content = encode_dm_base64(content: enc_message.bytes, iv: iv)
|
||||
let ev = NostrEvent(content: enc_content, pubkey: keypair.pubkey, kind: 4, tags: tags)
|
||||
let created = created_at ?? Int64(Date().timeIntervalSince1970)
|
||||
let ev = NostrEvent(content: enc_content, pubkey: keypair.pubkey, kind: 4, tags: tags, createdAt: created)
|
||||
|
||||
ev.calculate_id()
|
||||
ev.sign(privkey: privkey)
|
||||
return ev
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import SwiftUI
|
||||
|
||||
let PPM_SIZE: CGFloat = 80.0
|
||||
let BANNER_HEIGHT: CGFloat = 150.0;
|
||||
|
||||
func isHttpsUrl(_ string: String) -> Bool {
|
||||
let urlRegEx = "^https://.*$"
|
||||
@@ -56,12 +57,14 @@ struct EditMetadataView: View {
|
||||
@State var display_name: String
|
||||
@State var about: String
|
||||
@State var picture: String
|
||||
@State var banner: String
|
||||
@State var nip05: String
|
||||
@State var name: String
|
||||
@State var ln: String
|
||||
@State var website: String
|
||||
|
||||
@Environment(\.dismiss) var dismiss
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
|
||||
init (damus_state: DamusState) {
|
||||
self.damus_state = damus_state
|
||||
@@ -72,10 +75,15 @@ struct EditMetadataView: View {
|
||||
_about = State(initialValue: data?.about ?? "")
|
||||
_website = State(initialValue: data?.website ?? "")
|
||||
_picture = State(initialValue: data?.picture ?? "")
|
||||
_banner = State(initialValue: data?.banner ?? "")
|
||||
_nip05 = State(initialValue: data?.nip05 ?? "")
|
||||
_ln = State(initialValue: data?.lud16 ?? data?.lud06 ?? "")
|
||||
}
|
||||
|
||||
func imageBorderColor() -> Color {
|
||||
colorScheme == .light ? Color("DamusWhite") : Color("DamusBlack")
|
||||
}
|
||||
|
||||
func save() {
|
||||
let metadata = NostrMetadata(
|
||||
display_name: display_name,
|
||||
@@ -84,6 +92,7 @@ struct EditMetadataView: View {
|
||||
website: website,
|
||||
nip05: nip05.isEmpty ? nil : nip05,
|
||||
picture: picture.isEmpty ? nil : picture,
|
||||
banner: banner.isEmpty ? nil : banner,
|
||||
lud06: ln.contains("@") ? nil : ln,
|
||||
lud16: ln.contains("@") ? ln : nil
|
||||
);
|
||||
@@ -99,13 +108,32 @@ struct EditMetadataView: View {
|
||||
return NIP05.parse(nip05)
|
||||
}
|
||||
|
||||
var TopSection: some View {
|
||||
ZStack(alignment: .top) {
|
||||
GeometryReader { geo in
|
||||
BannerImageView(pubkey: damus_state.pubkey, profiles: damus_state.profiles)
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: geo.size.width, height: BANNER_HEIGHT)
|
||||
.clipped()
|
||||
}.frame(height: BANNER_HEIGHT)
|
||||
VStack(alignment: .leading) {
|
||||
let pfp_size: CGFloat = 90.0
|
||||
|
||||
HStack(alignment: .center) {
|
||||
ProfilePicView(pubkey: damus_state.pubkey, size: pfp_size, highlight: .custom(imageBorderColor(), 4.0), profiles: damus_state.profiles)
|
||||
.offset(y: -(pfp_size/2.0)) // Increase if set a frame
|
||||
|
||||
Spacer()
|
||||
}.padding(.bottom,-(pfp_size/2.0))
|
||||
}
|
||||
.padding(.horizontal,18)
|
||||
.padding(.top,BANNER_HEIGHT)
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
HStack {
|
||||
Spacer()
|
||||
InnerProfilePicView(url: URL(string: picture), fallbackUrl: nil, pubkey: damus_state.pubkey, size: PPM_SIZE, highlight: .none)
|
||||
Spacer()
|
||||
}
|
||||
TopSection
|
||||
Form {
|
||||
Section(NSLocalizedString("Your Name", comment: "Label for Your Name section of user profile form.")) {
|
||||
TextField("Satoshi Nakamoto", text: $display_name)
|
||||
@@ -126,6 +154,12 @@ struct EditMetadataView: View {
|
||||
.textInputAutocapitalization(.never)
|
||||
}
|
||||
|
||||
Section (NSLocalizedString("Banner Image", comment: "Label for Banner Image section of user profile form.")) {
|
||||
TextField(NSLocalizedString("https://example.com/pic.jpg", comment: "Placeholder example text for profile picture URL."), text: $banner)
|
||||
.autocorrectionDisabled(true)
|
||||
.textInputAutocapitalization(.never)
|
||||
}
|
||||
|
||||
Section(NSLocalizedString("Website", comment: "Label for Website section of user profile form.")) {
|
||||
TextField(NSLocalizedString("https://jb55.com", comment: "Placeholder example text for website URL for user profile."), text: $website)
|
||||
.autocorrectionDisabled(true)
|
||||
@@ -172,7 +206,7 @@ struct EditMetadataView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle(NSLocalizedString("Edit Profile", comment: "Title of navigation view for Edit Profile."))
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-15
@@ -172,20 +172,10 @@ struct EventView: View {
|
||||
let booster_profile = ProfileView(damus_state: damus, profile: prof_model, followers: follow_model)
|
||||
|
||||
NavigationLink(destination: booster_profile) {
|
||||
HStack {
|
||||
Image(systemName: "arrow.2.squarepath")
|
||||
.font(.footnote.weight(.bold))
|
||||
.foregroundColor(Color.gray)
|
||||
ProfileName(pubkey: event.pubkey, profile: prof, damus: damus, show_friend_confirmed: true)
|
||||
.font(.footnote.weight(.bold))
|
||||
.foregroundColor(Color.gray)
|
||||
Text("Boosted", comment: "Text indicating that the post was boosted (i.e. re-shared).")
|
||||
.font(.footnote.weight(.bold))
|
||||
.foregroundColor(Color.gray)
|
||||
}
|
||||
Reposted(damus: damus, pubkey: event.pubkey, profile: prof)
|
||||
}
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
TextEvent(inner_ev, pubkey: inner_ev.pubkey)
|
||||
TextEvent(inner_ev, pubkey: inner_ev.pubkey, booster_pubkey: event.pubkey)
|
||||
.padding([.top], 1)
|
||||
}
|
||||
} else {
|
||||
@@ -195,7 +185,7 @@ struct EventView: View {
|
||||
}
|
||||
}
|
||||
|
||||
func TextEvent(_ event: NostrEvent, pubkey: String) -> some View {
|
||||
func TextEvent(_ event: NostrEvent, pubkey: String, booster_pubkey: String? = nil) -> some View {
|
||||
let content = event.get_content(damus.keypair.privkey)
|
||||
|
||||
return HStack(alignment: .top) {
|
||||
@@ -242,7 +232,7 @@ struct EventView: View {
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
|
||||
let should_show_img = should_show_images(contacts: damus.contacts, ev: event, our_pubkey: damus.pubkey)
|
||||
let should_show_img = should_show_images(contacts: damus.contacts, ev: event, our_pubkey: damus.pubkey, booster_pubkey: booster_pubkey)
|
||||
|
||||
NoteContentView(privkey: damus.keypair.privkey, event: event, profiles: damus.profiles, previews: damus.previews, show_images: should_show_img, artifacts: .just_content(content), size: self.size)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
@@ -261,6 +251,13 @@ struct EventView: View {
|
||||
}
|
||||
|
||||
let bar = make_actionbar_model(ev: event, damus: damus)
|
||||
|
||||
if size == .selected && !bar.is_empty {
|
||||
EventDetailBar(state: damus, target: event.id, bar: bar)
|
||||
Divider()
|
||||
.padding([.bottom], 4)
|
||||
}
|
||||
|
||||
EventActionBar(damus_state: damus, event: event, bar: bar)
|
||||
}
|
||||
|
||||
@@ -279,13 +276,16 @@ struct EventView: View {
|
||||
}
|
||||
|
||||
// blame the porn bots for this code
|
||||
func should_show_images(contacts: Contacts, ev: NostrEvent, our_pubkey: String) -> Bool {
|
||||
func should_show_images(contacts: Contacts, ev: NostrEvent, our_pubkey: String, booster_pubkey: String? = nil) -> Bool {
|
||||
if ev.pubkey == our_pubkey {
|
||||
return true
|
||||
}
|
||||
if contacts.is_in_friendosphere(ev.pubkey) {
|
||||
return true
|
||||
}
|
||||
if let boost_key = booster_pubkey, contacts.is_in_friendosphere(boost_key) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ struct NoteContentView: View {
|
||||
return VStack(alignment: .leading) {
|
||||
Text(Markdown.parse(content: artifacts.content))
|
||||
.font(eventviewsize_to_font(size))
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
|
||||
if show_images && artifacts.images.count > 0 {
|
||||
ImageCarousel(urls: artifacts.images)
|
||||
@@ -90,8 +91,8 @@ struct NoteContentView: View {
|
||||
InvoicesView(invoices: artifacts.invoices)
|
||||
}
|
||||
|
||||
if show_images, self.preview != nil {
|
||||
self.preview
|
||||
if let preview = self.preview, show_images {
|
||||
preview
|
||||
} else {
|
||||
ForEach(artifacts.links, id:\.self) { link in
|
||||
if let url = link {
|
||||
|
||||
@@ -34,8 +34,6 @@ struct ProfileName: View {
|
||||
|
||||
@State var display_name: String?
|
||||
@State var nip05: NIP05?
|
||||
|
||||
@Environment(\.openURL) var openURL
|
||||
|
||||
init(pubkey: String, profile: Profile?, damus: DamusState, show_friend_confirmed: Bool, show_nip5_domain: Bool = true) {
|
||||
self.pubkey = pubkey
|
||||
@@ -73,18 +71,7 @@ struct ProfileName: View {
|
||||
.font(.body)
|
||||
.fontWeight(prefix == "@" ? .none : .bold)
|
||||
if let nip05 = current_nip05 {
|
||||
Image(systemName: "checkmark.seal.fill")
|
||||
.foregroundColor(nip05_color)
|
||||
|
||||
if show_nip5_domain {
|
||||
Text(nip05.host)
|
||||
.foregroundColor(nip05_color)
|
||||
.onTapGesture {
|
||||
if let nip5url = nip05.siteUrl {
|
||||
openURL(nip5url)
|
||||
}
|
||||
}
|
||||
}
|
||||
NIP05Badge(nip05: nip05, pubkey: pubkey, contacts: damus_state.contacts, show_domain: show_nip5_domain, clickable: true)
|
||||
}
|
||||
if let friend = friend_icon, current_nip05 == nil {
|
||||
Image(systemName: friend)
|
||||
@@ -158,9 +145,8 @@ struct EventProfileName: View {
|
||||
.fontWeight(.bold)
|
||||
}
|
||||
|
||||
if let _ = current_nip05 {
|
||||
Image(systemName: "checkmark.seal.fill")
|
||||
.foregroundColor(get_nip05_color(pubkey: pubkey, contacts: damus_state.contacts))
|
||||
if let nip05 = current_nip05 {
|
||||
NIP05Badge(nip05: nip05, pubkey: pubkey, contacts: damus_state.contacts, show_domain: false, clickable: false)
|
||||
}
|
||||
|
||||
if let frend = friend_icon, current_nip05 == nil {
|
||||
@@ -180,6 +166,3 @@ struct EventProfileName: View {
|
||||
}
|
||||
}
|
||||
|
||||
func get_nip05_color(pubkey: String, contacts: Contacts) -> Color {
|
||||
return contacts.is_friend_or_self(pubkey) ? .accentColor : .gray
|
||||
}
|
||||
|
||||
@@ -33,13 +33,23 @@ func pfp_line_width(_ h: Highlight) -> CGFloat {
|
||||
}
|
||||
|
||||
struct InnerProfilePicView: View {
|
||||
let url: URL?
|
||||
let fallbackUrl: URL?
|
||||
let pubkey: String
|
||||
let size: CGFloat
|
||||
let highlight: Highlight
|
||||
|
||||
@State private var refreshID = UUID().uuidString
|
||||
@ObservedObject var imageModel: KFImageModel
|
||||
|
||||
init(url: URL?, fallbackUrl: URL?, pubkey: String, size: CGFloat, highlight: Highlight) {
|
||||
self.pubkey = pubkey
|
||||
self.size = size
|
||||
self.highlight = highlight
|
||||
self.imageModel = KFImageModel(
|
||||
url: url,
|
||||
fallbackUrl: fallbackUrl,
|
||||
maxByteSize: 1000000,
|
||||
downsampleSize: CGSize(width: 200, height: 200)
|
||||
)
|
||||
}
|
||||
|
||||
var PlaceholderColor: Color {
|
||||
return id_to_color(pubkey)
|
||||
@@ -57,10 +67,12 @@ struct InnerProfilePicView: View {
|
||||
ZStack {
|
||||
Color(uiColor: .systemBackground)
|
||||
|
||||
KFAnimatedImage(url)
|
||||
KFAnimatedImage(imageModel.url)
|
||||
.callbackQueue(.dispatch(.global(qos: .background)))
|
||||
.processingQueue(.dispatch(.global(qos: .background)))
|
||||
.appendProcessor(LargeImageProcessor.shared)
|
||||
.serialize(by: imageModel.serializer)
|
||||
.setProcessor(imageModel.processor)
|
||||
.cacheOriginalImage()
|
||||
.configure { view in
|
||||
view.framePreloadCount = 1
|
||||
}
|
||||
@@ -71,42 +83,13 @@ struct InnerProfilePicView: View {
|
||||
.loadDiskFileSynchronously()
|
||||
.fade(duration: 0.1)
|
||||
.onFailure { _ in
|
||||
setFallbackImage()
|
||||
imageModel.downloadFailed()
|
||||
}
|
||||
.id(imageModel.refreshID)
|
||||
}
|
||||
.frame(width: size, height: size)
|
||||
.clipShape(Circle())
|
||||
.overlay(Circle().stroke(highlight_color(highlight), lineWidth: pfp_line_width(highlight)))
|
||||
.id(refreshID)
|
||||
}
|
||||
|
||||
func refreshView() -> Void {
|
||||
refreshID = UUID().uuidString
|
||||
}
|
||||
|
||||
func setFallbackImage() -> Void {
|
||||
|
||||
guard let url = url, let fallbackUrl = fallbackUrl else { return }
|
||||
|
||||
KingfisherManager.shared.downloader.downloadImage(with: fallbackUrl) { result in
|
||||
|
||||
func fallbackImage() -> UIImage {
|
||||
switch result {
|
||||
case .success(let imageLoadingResult):
|
||||
return imageLoadingResult.image
|
||||
case .failure(let error):
|
||||
print(error)
|
||||
return UIImage()
|
||||
}
|
||||
}
|
||||
|
||||
// Kingfisher ID format for caching when using a custom processor
|
||||
let processorIdentifier = "|>" + LargeImageProcessor.shared.identifier
|
||||
|
||||
KingfisherManager.shared.cache.store(fallbackImage(), forKey: url.absoluteString, processorIdentifier: processorIdentifier) { _ in
|
||||
refreshView()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,35 +125,6 @@ struct ProfilePicView: View {
|
||||
}
|
||||
}
|
||||
|
||||
struct LargeImageProcessor: ImageProcessor {
|
||||
|
||||
static let shared = LargeImageProcessor()
|
||||
|
||||
let identifier = "com.damus.largeimageprocessor"
|
||||
let maxSize: Int = 1000000
|
||||
let downsampleSize = CGSize(width: 200, height: 200)
|
||||
|
||||
func process(item: ImageProcessItem, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? {
|
||||
|
||||
switch item {
|
||||
case .image(let image):
|
||||
guard let data = image.kf.data(format: .unknown) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
if data.count > maxSize {
|
||||
return KingfisherWrapper.downsampledImage(data: data, to: downsampleSize, scale: options.scaleFactor)
|
||||
}
|
||||
return image
|
||||
case .data(let data):
|
||||
if data.count > maxSize {
|
||||
return KingfisherWrapper.downsampledImage(data: data, to: downsampleSize, scale: options.scaleFactor)
|
||||
}
|
||||
return KFCrossPlatformImage(data: data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func get_profile_url(picture: String?, pubkey: String, profiles: Profiles) -> URL {
|
||||
let pic = picture ?? profiles.lookup(id: pubkey)?.picture ?? robohash(pubkey)
|
||||
if let url = URL(string: pic) {
|
||||
@@ -182,7 +136,7 @@ func get_profile_url(picture: String?, pubkey: String, profiles: Profiles) -> UR
|
||||
func make_preview_profiles(_ pubkey: String) -> Profiles {
|
||||
let profiles = Profiles()
|
||||
let picture = "http://cdn.jb55.com/img/red-me.jpg"
|
||||
let profile = Profile(name: "jb55", display_name: "William Casarin", about: "It's me", picture: picture, website: "https://jb55.com", lud06: nil, lud16: nil, nip05: "jb55.com")
|
||||
let profile = Profile(name: "jb55", display_name: "William Casarin", about: "It's me", picture: picture, banner: "", website: "https://jb55.com", lud06: nil, lud16: nil, nip05: "jb55.com")
|
||||
let ts_profile = TimestampedProfile(profile: profile, timestamp: 0)
|
||||
profiles.add(id: pubkey, profile: ts_profile)
|
||||
return profiles
|
||||
|
||||
@@ -194,15 +194,14 @@ struct ProfileView: View {
|
||||
var TopSection: some View {
|
||||
ZStack(alignment: .top) {
|
||||
GeometryReader { geo in
|
||||
Image("profile-banner")
|
||||
.resizable()
|
||||
BannerImageView(pubkey: profile.pubkey, profiles: damus_state.profiles)
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: geo.size.width, height: 150)
|
||||
.frame(width: geo.size.width, height: BANNER_HEIGHT)
|
||||
.clipped()
|
||||
|
||||
ShareButton
|
||||
.offset(x: geo.size.width - 80.0, y: 50.0 )
|
||||
}
|
||||
}.frame(height: BANNER_HEIGHT)
|
||||
VStack(alignment: .leading) {
|
||||
let data = damus_state.profiles.lookup(id: profile.pubkey)
|
||||
let pfp_size: CGFloat = 90.0
|
||||
@@ -283,7 +282,7 @@ struct ProfileView: View {
|
||||
|
||||
if let relays = profile.relays {
|
||||
NavigationLink(destination: UserRelaysView(state: damus_state, pubkey: profile.pubkey, relays: Array(relays.keys).sorted())) {
|
||||
Text("\(Text("\(relays.keys.count)", comment: "Number of relay servers a user is connected.").font(.subheadline.weight(.medium))) \(Text("Relays", comment: "Part of a larger sentence to describe how many relay servers a user is connected.").font(.subheadline).foregroundColor(.gray))", comment: "Sentence composed of 2 variables to describe how many relay servers a user is connected. In source English, the first variable is the number of relay servers, and the second variable is 'Relays'.")
|
||||
Text("\(Text("\(relays.keys.count)", comment: "Number of relay servers a user is connected.").font(.subheadline.weight(.medium))) \(Text(String(format: NSLocalizedString("relays_count", comment: "Part of a larger sentence to describe how many relay servers a user is connected."), relays.keys.count)).font(.subheadline).foregroundColor(.gray))", comment: "Sentence composed of 2 variables to describe how many relay servers a user is connected. In source English, the first variable is the number of relay servers, and the second variable is 'Relay' or 'Relays'.")
|
||||
}
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
}
|
||||
@@ -297,13 +296,14 @@ struct ProfileView: View {
|
||||
|
||||
var FollowersCount: some View {
|
||||
HStack {
|
||||
if followers.count_display == "?" {
|
||||
if followers.count == nil {
|
||||
Image(systemName: "square.and.arrow.down")
|
||||
Text("Followers", comment: "Label describing followers of a user.")
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.gray)
|
||||
} else {
|
||||
Text("\(Text("\(followers.count_display)", comment: "Number of people following a user.").font(.subheadline.weight(.medium))) \(Text("Followers", comment: "Part of a larger sentence to describe how many people are following a user.").font(.subheadline).foregroundColor(.gray))", comment: "Sentence composed of 2 variables to describe how many people are following a user. In source English, the first variable is the number of followers, and the second variable is 'Followers'.")
|
||||
let followerCount = followers.count!
|
||||
Text("\(Text("\(followerCount)", comment: "Number of people following a user.").font(.subheadline.weight(.medium))) \(Text(String(format: NSLocalizedString("followers_count", comment: "Part of a larger sentence to describe how many people are following a user."), followerCount)).font(.subheadline).foregroundColor(.gray))", comment: "Sentence composed of 2 variables to describe how many people are following a user. In source English, the first variable is the number of followers, and the second variable is 'Follower' or 'Followers'.")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -358,7 +358,7 @@ func test_damus_state() -> DamusState {
|
||||
let pubkey = "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"
|
||||
let damus = DamusState(pool: RelayPool(), keypair: Keypair(pubkey: pubkey, privkey: "privkey"), likes: EventCounter(our_pubkey: pubkey), boosts: EventCounter(our_pubkey: pubkey), contacts: Contacts(our_pubkey: pubkey), tips: TipCounter(our_pubkey: pubkey), profiles: Profiles(), dms: DirectMessagesModel(), previews: PreviewCache())
|
||||
|
||||
let prof = Profile(name: "damus", display_name: "damus", about: "iOS app!", picture: "https://damus.io/img/logo.png", website: "https://damus.io", lud06: nil, lud16: "jb55@sendsats.lol", nip05: "damus.io")
|
||||
let prof = Profile(name: "damus", display_name: "damus", about: "iOS app!", picture: "https://damus.io/img/logo.png", banner: "", website: "https://damus.io", lud06: nil, lud16: "jb55@sendsats.lol", nip05: "damus.io")
|
||||
let tsprof = TimestampedProfile(profile: prof, timestamp: 0)
|
||||
damus.profiles.add(id: pubkey, profile: tsprof)
|
||||
return damus
|
||||
|
||||
@@ -14,7 +14,7 @@ struct PubkeyView: View {
|
||||
var body: some View {
|
||||
let color: Color = id_to_color(pubkey)
|
||||
ZStack {
|
||||
Text("\(abbrev_pubkey(pubkey))")
|
||||
Text("\(abbrev_pubkey(pubkey))", comment: "Abbreviated version of a nostr public key.")
|
||||
.foregroundColor(color)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// ReactionView.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-01-11.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ReactionView: View {
|
||||
let damus_state: DamusState
|
||||
let reaction: NostrEvent
|
||||
|
||||
var content: String {
|
||||
if reaction.content == "" || reaction.content == "+" {
|
||||
return "❤️"
|
||||
}
|
||||
return reaction.content
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
Text(content)
|
||||
.font(Font.headline)
|
||||
.frame(width: 50, height: 50)
|
||||
|
||||
FollowUserView(target: .pubkey(reaction.pubkey), damus_state: damus_state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ReactionView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ReactionView(damus_state: test_damus_state(), reaction: NostrEvent(id: "", content: "🤙🏼", pubkey: ""))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// ReactionsView.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-01-11.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ReactionsView: View {
|
||||
let damus_state: DamusState
|
||||
@StateObject var model: ReactionsModel
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
LazyVStack {
|
||||
ForEach(model.reactions, id: \.id) { ev in
|
||||
ReactionView(damus_state: damus_state, reaction: ev)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.navigationBarTitle(NSLocalizedString("Reactions", comment: "Navigation bar title for Reactions view."))
|
||||
.onAppear {
|
||||
model.subscribe()
|
||||
}
|
||||
.onDisappear {
|
||||
model.unsubscribe()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ReactionsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let state = test_damus_state()
|
||||
ReactionsView(damus_state: state, model: ReactionsModel(state: state, target: "pubkey"))
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ struct ReplyQuoteView: View {
|
||||
ProfilePicView(pubkey: event.pubkey, size: 16, highlight: .reply, profiles: profiles)
|
||||
Text(Profile.displayName(profile: profiles.lookup(id: event.pubkey), pubkey: event.pubkey))
|
||||
.foregroundColor(.accentColor)
|
||||
Text("\(format_relative_time(event.created_at))")
|
||||
Text("\(format_relative_time(event.created_at))", comment: "Amount of time that has passed since reply quote event occurred.")
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ struct SaveKeysView: View {
|
||||
} else if let err = error {
|
||||
Text("Error: \(err)", comment: "Error message indicating why saving keys failed.")
|
||||
.foregroundColor(.red)
|
||||
DamusWhiteButton("Retry") {
|
||||
DamusWhiteButton(NSLocalizedString("Retry", comment: "Button to retry completing account creation after an error occurred.")) {
|
||||
complete_account_creation(account)
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -42,6 +42,7 @@ struct SearchView_Previews: PreviewProvider {
|
||||
let test_state = test_damus_state()
|
||||
let filter = NostrFilter.filter_hashtag(["bitcoin"])
|
||||
let pool = test_state.pool
|
||||
|
||||
let model = SearchModel(pool: pool, search: filter)
|
||||
|
||||
SearchView(appstate: test_state, search: model)
|
||||
|
||||
@@ -64,7 +64,7 @@ struct SetupView: View {
|
||||
self.state = .create_account
|
||||
}
|
||||
|
||||
Button("Login") {
|
||||
Button(NSLocalizedString("Login", comment: "Button to log into an account.")) {
|
||||
self.state = .login
|
||||
}
|
||||
.padding([.top, .bottom], 20)
|
||||
|
||||
@@ -50,9 +50,13 @@ struct SideMenuView: View {
|
||||
|
||||
VStack(alignment: .leading, spacing: 20) {
|
||||
let profile = damus_state.profiles.lookup(id: damus_state.pubkey)
|
||||
let followers = FollowersModel(damus_state: damus_state, target: damus_state.pubkey)
|
||||
let profile_model = ProfileModel(pubkey: damus_state.pubkey, damus: damus_state)
|
||||
|
||||
if let picture = damus_state.profiles.lookup(id: damus_state.pubkey)?.picture {
|
||||
ProfilePicView(pubkey: damus_state.pubkey, size: 60, highlight: .none, profiles: damus_state.profiles, picture: picture)
|
||||
NavigationLink(destination: ProfileView(damus_state: damus_state, profile: profile_model, followers: followers)) {
|
||||
ProfilePicView(pubkey: damus_state.pubkey, size: 60, highlight: .none, profiles: damus_state.profiles, picture: picture)
|
||||
}
|
||||
} else {
|
||||
Image(systemName: "person.fill")
|
||||
}
|
||||
@@ -87,12 +91,9 @@ struct SideMenuView: View {
|
||||
*/
|
||||
|
||||
// THERE IS A LIMIT OF 10 NAVIGATIONLINKS!!! (Consider some in other views)
|
||||
|
||||
let followers = FollowersModel(damus_state: damus_state, target: damus_state.pubkey)
|
||||
let profile_model = ProfileModel(pubkey: damus_state.pubkey, damus: damus_state)
|
||||
|
||||
NavigationLink(destination: ProfileView(damus_state: damus_state, profile: profile_model, followers: followers)) {
|
||||
Label("Profile", systemImage: "person")
|
||||
Label(NSLocalizedString("Profile", comment: "Sidebar menu label for Profile view."), systemImage: "person")
|
||||
.font(.title2)
|
||||
.foregroundColor(textColor())
|
||||
}
|
||||
@@ -102,7 +103,7 @@ struct SideMenuView: View {
|
||||
|
||||
/*
|
||||
NavigationLink(destination: EmptyView()) {
|
||||
Label("Relays", systemImage: "xserve")
|
||||
Label(NSLocalizedString("Relays", comment: "Sidebar menu label for Relay servers view"), systemImage: "xserve")
|
||||
.font(.title2)
|
||||
.foregroundColor(textColor())
|
||||
}
|
||||
@@ -113,7 +114,7 @@ struct SideMenuView: View {
|
||||
|
||||
/*
|
||||
NavigationLink(destination: EmptyView()) {
|
||||
Label("Wallet", systemImage: "bolt")
|
||||
Label(NSLocalizedString("Wallet", comment: "Sidebar menu label for Wallet view."), systemImage: "bolt")
|
||||
.font(.title2)
|
||||
.foregroundColor(textColor())
|
||||
}
|
||||
@@ -135,9 +136,13 @@ struct SideMenuView: View {
|
||||
|
||||
Button(action: {
|
||||
//ConfigView(state: damus_state)
|
||||
confirm_logout = true
|
||||
if damus_state.keypair.privkey == nil {
|
||||
notify(.logout, ())
|
||||
} else {
|
||||
confirm_logout = true
|
||||
}
|
||||
}, label: {
|
||||
Label("Sign out", systemImage: "pip.exit")
|
||||
Label(NSLocalizedString("Sign out", comment: "Sidebar menu label to sign out of the account."), systemImage: "pip.exit")
|
||||
.font(.title3)
|
||||
.foregroundColor(textColor())
|
||||
})
|
||||
@@ -153,14 +158,14 @@ struct SideMenuView: View {
|
||||
isSidebarVisible.toggle()
|
||||
}
|
||||
.alert("Logout", isPresented: $confirm_logout) {
|
||||
Button("Cancel") {
|
||||
Button(NSLocalizedString("Cancel", comment: "Cancel out of logging out the user.")) {
|
||||
confirm_logout = false
|
||||
}
|
||||
Button("Logout") {
|
||||
Button(NSLocalizedString("Logout", comment: "Button for logging out the user.")) {
|
||||
notify(.logout, ())
|
||||
}
|
||||
} message: {
|
||||
Text("Make sure your nsec account key is saved before you logout or you will lose access to this account")
|
||||
Text("Make sure your nsec account key is saved before you logout or you will lose access to this account", comment: "Reminder message in alert to get customer to verify that their private security account key is saved saved before logging out.")
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
@@ -2,6 +2,70 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>collapsed_event_view_other_notes</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>··· %#@NOTES@ ···</string>
|
||||
<key>NOTES</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%d other note</string>
|
||||
<key>other</key>
|
||||
<string>%d other notes</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>followers_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@FOLLOWERS@</string>
|
||||
<key>FOLLOWERS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Follower</string>
|
||||
<key>other</key>
|
||||
<string>Followers</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>reactions_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@REACTIONS@</string>
|
||||
<key>REACTIONS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Reaction</string>
|
||||
<key>other</key>
|
||||
<string>Reactions</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>relays_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@RELAYS@</string>
|
||||
<key>RELAYS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Relay</string>
|
||||
<key>other</key>
|
||||
<string>Relays</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>replying_to_one_and_others</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
@@ -15,7 +79,7 @@
|
||||
<key>zero</key>
|
||||
<string></string>
|
||||
<key>one</key>
|
||||
<string> & 1 other</string>
|
||||
<string> & %d other</string>
|
||||
<key>other</key>
|
||||
<string> & %d others</string>
|
||||
</dict>
|
||||
@@ -33,27 +97,57 @@
|
||||
<key>zero</key>
|
||||
<string></string>
|
||||
<key>one</key>
|
||||
<string> & 1 other</string>
|
||||
<string> & %d other</string>
|
||||
<key>other</key>
|
||||
<string> & %d others</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>collapsed_event_view_other_notes</key>
|
||||
<key>reposts_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>··· %#@NOTES@ ···</string>
|
||||
<key>NOTES</key>
|
||||
<string>%#@REPOSTS@</string>
|
||||
<key>REPOSTS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>zero</key>
|
||||
<string>0 other notes</string>
|
||||
<key>one</key>
|
||||
<string>1 other note</string>
|
||||
<string>Repost</string>
|
||||
<key>other</key>
|
||||
<string>%d other notes</string>
|
||||
<string>Reposts</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>sats_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%1$#@SATS@</string>
|
||||
<key>SATS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>@</string>
|
||||
<key>one</key>
|
||||
<string>%2$@ sat</string>
|
||||
<key>other</key>
|
||||
<string>%2$@ sats</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>tips_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@TIPS@</string>
|
||||
<key>TIPS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Tip</string>
|
||||
<key>other</key>
|
||||
<string>Tips</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
|
||||
@@ -2,6 +2,70 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>collapsed_event_view_other_notes</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>··· %#@NOTES@ ···</string>
|
||||
<key>NOTES</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%d other note</string>
|
||||
<key>other</key>
|
||||
<string>%d other notes</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>followers_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@FOLLOWERS@</string>
|
||||
<key>FOLLOWERS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Follower</string>
|
||||
<key>other</key>
|
||||
<string>Followers</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>reactions_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@REACTIONS@</string>
|
||||
<key>REACTIONS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Reaction</string>
|
||||
<key>other</key>
|
||||
<string>Reactions</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>relays_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@RELAYS@</string>
|
||||
<key>RELAYS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Relay</string>
|
||||
<key>other</key>
|
||||
<string>Relays</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>replying_to_one_and_others</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
@@ -15,7 +79,7 @@
|
||||
<key>zero</key>
|
||||
<string></string>
|
||||
<key>one</key>
|
||||
<string> & 1 other</string>
|
||||
<string> & %d other</string>
|
||||
<key>other</key>
|
||||
<string> & %d others</string>
|
||||
</dict>
|
||||
@@ -33,27 +97,57 @@
|
||||
<key>zero</key>
|
||||
<string></string>
|
||||
<key>one</key>
|
||||
<string> & 1 other</string>
|
||||
<string> & %d other</string>
|
||||
<key>other</key>
|
||||
<string> & %d others</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>collapsed_event_view_other_notes</key>
|
||||
<key>reposts_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>··· %#@NOTES@ ···</string>
|
||||
<key>NOTES</key>
|
||||
<string>%#@REPOSTS@</string>
|
||||
<key>REPOSTS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>zero</key>
|
||||
<string>0 notes</string>
|
||||
<key>one</key>
|
||||
<string>1 note</string>
|
||||
<string>Repost</string>
|
||||
<key>other</key>
|
||||
<string>%d notes</string>
|
||||
<string>Reposts</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>sats_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%1$#@SATS@</string>
|
||||
<key>SATS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>@</string>
|
||||
<key>one</key>
|
||||
<string>%2$@ sat</string>
|
||||
<key>other</key>
|
||||
<string>%2$@ sats</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>tips_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@TIPS@</string>
|
||||
<key>TIPS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Tip</string>
|
||||
<key>other</key>
|
||||
<string>Tips</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
//
|
||||
// DMTests.swift
|
||||
// damusTests
|
||||
//
|
||||
// Created by William Casarin on 2023-01-14.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import damus
|
||||
|
||||
final class DMTests: XCTestCase {
|
||||
|
||||
override func setUpWithError() throws {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
var alice: Keypair {
|
||||
let sec = "494c680d20f202807a116a6915815bd76a27d62802e7585806f6a2e034cb5cdb"
|
||||
let pk = "22d925632551a3299022e98de7f9c1087f79a21209f3413ec24ec219b08bd1e4"
|
||||
return Keypair(pubkey: pk, privkey: sec)
|
||||
}
|
||||
|
||||
var bob: Keypair {
|
||||
let sec = "aa8920b05b4bd5c79fce46868ed5ebc82bdb91b211850b14541bfbd13953cfef"
|
||||
let pk = "5a9a277dca94260688ecf7d63053de8c121b7f01f609d7f84a1eb9cff64e4606"
|
||||
return Keypair(pubkey: pk, privkey: sec)
|
||||
}
|
||||
|
||||
var charlie: Keypair {
|
||||
let sec = "4c79130952c9c3b017dad62f37f285853a9c53f2a1184d94594f5b860f30b5a5"
|
||||
let pk = "51c0d263fbfc4bf850805dccf9a29125071e6fed9619bff3efa9a6b5bbcc54a7"
|
||||
return Keypair(pubkey: pk, privkey: sec)
|
||||
}
|
||||
|
||||
var dave: Keypair {
|
||||
let sec = "630ffd518084334cbb9ecb20d9532ce0658b8123f4ba565c236d0cea9a4a2cfe"
|
||||
let pk = "b42e44b555013239a0d5dcdb09ebde0857cd8a5a57efbba5a2b6ac78833cb9f0"
|
||||
return Keypair(pubkey: pk, privkey: sec)
|
||||
}
|
||||
|
||||
var fiatjaf: Keypair {
|
||||
let sec = "5426893eab32191ec17a83a583d5c8f85adaabcab0fa56af277ea0b61f575599"
|
||||
let pub = "e27258d7be6d84038967334bfd0954f05801b1bcd85b2afa4c03cfd16ae4b0ad"
|
||||
return Keypair(pubkey: pub, privkey: sec)
|
||||
}
|
||||
|
||||
func testDMSortOrder() throws {
|
||||
let notif = NewEventsBits()
|
||||
let model = DirectMessagesModel()
|
||||
|
||||
let now = Int64(Date().timeIntervalSince1970)
|
||||
|
||||
let alice_to_bob = create_dm("hi bob", to_pk: bob.pubkey, tags: [["p", bob.pubkey]], keypair: alice, created_at: now)!
|
||||
let _ = handle_incoming_dm(prev_events: notif, dms: model, our_pubkey: alice.pubkey, ev: alice_to_bob)
|
||||
|
||||
XCTAssertEqual(model.dms.count, 1)
|
||||
XCTAssertEqual(model.dms[0].0, bob.pubkey)
|
||||
|
||||
let bob_to_alice = create_dm("hi alice", to_pk: alice.pubkey, tags: [["p", alice.pubkey]], keypair: bob, created_at: now + 1)!
|
||||
let _ = handle_incoming_dm(prev_events: notif, dms: model, our_pubkey: alice.pubkey, ev: bob_to_alice)
|
||||
|
||||
XCTAssertEqual(model.dms.count, 1)
|
||||
XCTAssertEqual(model.dms[0].0, bob.pubkey)
|
||||
|
||||
let alice_to_bob_2 = create_dm("hi bob", to_pk: bob.pubkey, tags: [["p", bob.pubkey]], keypair: alice, created_at: now + 2)!
|
||||
let _ = handle_incoming_dm(prev_events: notif, dms: model, our_pubkey: alice.pubkey, ev: alice_to_bob_2)
|
||||
|
||||
XCTAssertEqual(model.dms.count, 1)
|
||||
XCTAssertEqual(model.dms[0].0, bob.pubkey)
|
||||
|
||||
let fiatjaf_to_alice = create_dm("hi alice", to_pk: alice.pubkey, tags: [["p", alice.pubkey]], keypair: fiatjaf, created_at: now+5)!
|
||||
let _ = handle_incoming_dm(prev_events: notif, dms: model, our_pubkey: alice.pubkey, ev: fiatjaf_to_alice)
|
||||
|
||||
XCTAssertEqual(model.dms.count, 2)
|
||||
XCTAssertEqual(model.dms[0].0, fiatjaf.pubkey)
|
||||
|
||||
let dave_to_alice = create_dm("hi alice", to_pk: alice.pubkey, tags: [["p", alice.pubkey]], keypair: dave, created_at: now + 10)!
|
||||
let _ = handle_incoming_dm(prev_events: notif, dms: model, our_pubkey: alice.pubkey, ev: dave_to_alice)
|
||||
|
||||
XCTAssertEqual(model.dms.count, 3)
|
||||
XCTAssertEqual(model.dms[0].0, dave.pubkey)
|
||||
|
||||
let bob_to_alice_2 = create_dm("hi alice 2", to_pk: alice.pubkey, tags: [["p", alice.pubkey]], keypair: bob, created_at: now + 15)!
|
||||
let _ = handle_incoming_dm(prev_events: notif, dms: model, our_pubkey: alice.pubkey, ev: bob_to_alice_2)
|
||||
|
||||
XCTAssertEqual(model.dms.count, 3)
|
||||
XCTAssertEqual(model.dms[0].0, bob.pubkey)
|
||||
|
||||
let charlie_to_alice = create_dm("hi alice", to_pk: alice.pubkey, tags: [["p", alice.pubkey]], keypair: charlie, created_at: now + 20)!
|
||||
let _ = handle_incoming_dm(prev_events: notif, dms: model, our_pubkey: alice.pubkey, ev: charlie_to_alice)
|
||||
|
||||
XCTAssertEqual(model.dms.count, 4)
|
||||
XCTAssertEqual(model.dms[0].0, charlie.pubkey)
|
||||
|
||||
let bob_to_alice_3 = create_dm("hi alice 3", to_pk: alice.pubkey, tags: [["p", alice.pubkey]], keypair: bob, created_at: now + 25)!
|
||||
let _ = handle_incoming_dm(prev_events: notif, dms: model, our_pubkey: alice.pubkey, ev: bob_to_alice_3)
|
||||
|
||||
XCTAssertEqual(model.dms.count, 4)
|
||||
XCTAssertEqual(model.dms[0].0, bob.pubkey)
|
||||
|
||||
let charlie_to_alice_2 = create_dm("hi alice 2", to_pk: alice.pubkey, tags: [["p", alice.pubkey]], keypair: charlie, created_at: now + 30)!
|
||||
let _ = handle_incoming_dm(prev_events: notif, dms: model, our_pubkey: alice.pubkey, ev: charlie_to_alice_2)
|
||||
|
||||
XCTAssertEqual(model.dms.count, 4)
|
||||
XCTAssertEqual(model.dms[0].0, charlie.pubkey)
|
||||
|
||||
|
||||
//let alice_to_bob_2 = create_dm("whats up", to_pk: bob.pubkey, tags: [], keypair: alice, created_at: now + 6)
|
||||
|
||||
//let charlie_to_alice = create_dm("hi alice", to_pk: alice.pubkey, tags: [], keypair: charlie, created_at: now + 7)
|
||||
//let alice_to_charlie = create_dm("hey charlie", to_pk: charlie.pubkey, tags[], keypair: alice, created_at: now + 8)
|
||||
|
||||
//handle_incoming_dm(prev_events: notif, dms: model, our_pubkey: pk, ev: ev)
|
||||
}
|
||||
|
||||
func testPerformanceExample() throws {
|
||||
// This is an example of a performance test case.
|
||||
self.measure {
|
||||
// Put the code you want to measure the time of here.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+5
-5
@@ -6,8 +6,8 @@ git:
|
||||
source_file: damus Localizations/en-US.xcloc/Localized Contents/en-US.xliff
|
||||
translation_files_expression: damus Localizations/<lang>.xcloc/Localized Contents/<lang>.xliff
|
||||
|
||||
settings:
|
||||
pr_branch_name: transifex/<br_unique_id>
|
||||
language_mapping:
|
||||
en_US: en-US
|
||||
es_419: es-419
|
||||
settings:
|
||||
pr_branch_name: transifex/<br_unique_id>
|
||||
language_mapping:
|
||||
en_US: en-US
|
||||
es_419: es-419
|
||||
Reference in New Issue
Block a user