Compare commits
82 Commits
tyiu/expor
...
tyiu/repos
| Author | SHA1 | Date | |
|---|---|---|---|
|
ae81575386
|
|||
|
|
209a1c3213 | ||
|
|
675903b768 | ||
|
|
92035e17d3 | ||
|
|
8df5bf04ae | ||
|
|
7e1daf7816 | ||
|
|
0ead583bda | ||
|
|
dd44bd779b | ||
|
|
c31374fc0a | ||
|
|
f3730630b5 | ||
|
d5f2a17249
|
|||
|
4526ed01fe
|
|||
|
|
a590fb099d | ||
|
|
135814737c | ||
|
e2e60639d9
|
|||
|
83909c8fc9
|
|||
|
|
3e4914462b | ||
|
|
7a11433a98 | ||
|
|
03e1c1903f | ||
|
|
acdee6a326 | ||
|
|
f5e03f145c | ||
|
|
2a9ddd10c8 | ||
| 5e9580377d | |||
|
|
9d2ff2fe65 | ||
|
|
13ea42a2e2 | ||
|
|
d9e22ce7bf | ||
|
|
2335a65b78 | ||
|
|
566cd141ce | ||
|
|
55f7f8c072 | ||
|
|
4b4addd215 | ||
|
|
255a0c55ba | ||
|
|
ced6e2488f | ||
|
|
77c2abc524 | ||
|
|
e4ad15ced1 | ||
|
|
904a6e960a | ||
|
da8a82954a
|
|||
|
383f45fe96
|
|||
|
9dc0f3baf6
|
|||
|
abc857582f
|
|||
|
|
4816b57dcd | ||
|
|
06b1953b49 | ||
|
|
d658d1d987 | ||
|
|
e14cd99c85 | ||
|
|
0258ef792f | ||
|
|
52524e00a2 | ||
|
|
342883fbb0 | ||
|
|
1e6505abe3 | ||
|
|
98c24147e8 | ||
|
|
d1e7de5dcb | ||
|
|
11e0a87f06 | ||
|
|
1154cec719 | ||
|
|
1ecfb0487e | ||
|
|
8ffa8446b6 | ||
|
|
fb1f99e728 | ||
|
|
031408dec3 | ||
|
|
16b6d029fa | ||
|
|
3e093e8572 | ||
|
|
fa11af4b1d | ||
|
|
91159d70ca | ||
|
|
a57d654f32 | ||
|
|
0313480685 | ||
|
|
e07b31e0a1 | ||
|
538a0ae5ea
|
|||
|
0f82db2440
|
|||
|
|
92ae2c7754 | ||
|
|
00c819140b | ||
|
|
cbc3c46c9d | ||
|
|
4b5c34b4e2 | ||
|
|
9eb39f7e0a | ||
| 173b22b772 | |||
|
|
18c7cba53c | ||
|
|
9a40fd595d | ||
|
|
a71c35a6b0 | ||
|
|
d69d3cc74e | ||
|
|
6e220ac4c1 | ||
|
|
bcb40a6ec7 | ||
|
|
2f1063b49f | ||
|
|
73110952e5 | ||
| d01e7c0595 | |||
|
|
aba758b143 | ||
|
|
b7c7b0b3bf | ||
|
|
2d10d4592b |
30
.github/workflows/run-tests.yaml
vendored
30
.github/workflows/run-tests.yaml
vendored
@@ -1,4 +1,6 @@
|
||||
name: Test
|
||||
name: Run Test Suite
|
||||
run-name: Testing ${{ github.ref }} by @${{ github.actor }}
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
@@ -6,12 +8,24 @@ on:
|
||||
pull_request:
|
||||
branches:
|
||||
- "*"
|
||||
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Run Tests
|
||||
runs-on: macos-latest
|
||||
run_tests:
|
||||
runs-on: macos-12
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- xcode: "14.2"
|
||||
ios: "16.2"
|
||||
|
||||
name: Test iOS (${{ matrix.ios }})
|
||||
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]}
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
- name: Select Xcode
|
||||
uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: ${{ matrix.xcode }}
|
||||
- name: Run Tests
|
||||
run: xcodebuild test -scheme damus -project damus.xcodeproj -destination 'platform=iOS Simulator,name=iPhone 14,OS=${{ matrix.ios }}' | xcpretty && exit ${PIPESTATUS[0]}
|
||||
55
CHANGELOG.md
55
CHANGELOG.md
@@ -1,3 +1,57 @@
|
||||
## [1.0.0-8] - 2023-01-22
|
||||
|
||||
### Added
|
||||
|
||||
- Show website on profiles (William Casarin)
|
||||
- Add the ability to choose participants when replying (Joel Klabo)
|
||||
- Translations for de_AT, de_DE, tr_TR, fr_FR (William Casarin)
|
||||
- Add DM Message Requests (William Casarin)
|
||||
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix commands and emojis getting included in hashtags (William Casarin)
|
||||
- Fix duplicate post buttons when swiping tabs (Thomas Rademaker)
|
||||
- Show embedded note references (William Casarin)
|
||||
|
||||
|
||||
[1.0.0-8]: https://github.com/damus-io/damus/releases/tag/v1.0.0-8
|
||||
|
||||
|
||||
## [1.0.0-7] - 2023-01-20
|
||||
|
||||
### Added
|
||||
|
||||
- Drastically improved image viewer (OlegAba)
|
||||
- Added pinch to zoom on images (Swift)
|
||||
- Add Latin American Spanish translations (William Casarin)
|
||||
- Added SVG profile picture support (OlegAba)
|
||||
|
||||
|
||||
### Changed
|
||||
|
||||
- Makes both name and username clickable in sidebar to go to profile (Zach Hendel)
|
||||
- Clicking pfp in sidebar opens profile as well (radixrat)
|
||||
- Don't blur images if your friend boosted it (ericholguin)
|
||||
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix ... when too many likes/reposts (Joel Klabo)
|
||||
- Don't show report alert if logged in as a pubkey (Swift)
|
||||
- Fix padding issue at top of home timeline (Ben Weeks)
|
||||
- Fix absurdly large sidebar on Mac/iPad (John Bethancourt)
|
||||
- Fix tab views moving after selecting from search result (OlegAba)
|
||||
- Make follow/unfollow button a consistent width (OlegAba)
|
||||
- Don't add events to notifications from buggy relays (William Casarin)
|
||||
- Fixed some crashes with large images (OlegAba)
|
||||
- Fix DM sorting on incoming messages (William Casarin)
|
||||
- Fix text getting truncated next to link previews (William Casarin)
|
||||
|
||||
|
||||
[1.0.0-7]: https://github.com/damus-io/damus/releases/tag/v1.0.0-7
|
||||
|
||||
|
||||
## [1.0.0-6] - 2023-01-13
|
||||
|
||||
### Added
|
||||
@@ -384,4 +438,3 @@
|
||||
[0.1.2]: https://github.com/damus-io/damus/releases/tag/v0.1.2
|
||||
|
||||
|
||||
|
||||
|
||||
1246
damus Localizations/de_AT.xcloc/Localized Contents/de_AT.xliff
Normal file
1246
damus Localizations/de_AT.xcloc/Localized Contents/de_AT.xliff
Normal file
File diff suppressed because it is too large
Load Diff
1246
damus Localizations/de_DE.xcloc/Localized Contents/de_DE.xliff
Normal file
1246
damus Localizations/de_DE.xcloc/Localized Contents/de_DE.xliff
Normal file
File diff suppressed because it is too large
Load Diff
@@ -16,8 +16,8 @@
|
||||
<note>Bundle name</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="NSPhotoLibraryAddUsageDescription" xml:space="preserve">
|
||||
<source>"Granting Damus access to your photo library allows you to save photos.</source>
|
||||
<target>"Granting Damus access to your photo library allows you to save photos.</target>
|
||||
<source>Granting Damus access to your photos allows you to save images.</source>
|
||||
<target>Granting Damus access to your photos allows you to save images.</target>
|
||||
<note>Privacy - Photo Library Additions Usage Description</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
@@ -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>
|
||||
@@ -143,15 +131,25 @@
|
||||
<target>Add Relay</target>
|
||||
<note>Label for section for adding a relay server.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Add all" xml:space="preserve">
|
||||
<source>Add all</source>
|
||||
<target>Add all</target>
|
||||
<note>Button label to re-add all original participants as profiles to reply to in a note</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Any" xml:space="preserve">
|
||||
<source>Any</source>
|
||||
<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 +176,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 +190,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>
|
||||
@@ -297,10 +285,16 @@
|
||||
<target>Creator(s) of Bitcoin. Absolute legend.</target>
|
||||
<note>Example description about Bitcoin creator(s), Satoshi Nakamoto.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DM" xml:space="preserve">
|
||||
<source>DM</source>
|
||||
<target>DM</target>
|
||||
<note>Navigation title for DM view, which is the English abbreviation for Direct Message.</note>
|
||||
<trans-unit id="DM Type" xml:space="preserve">
|
||||
<source>DM Type</source>
|
||||
<target>DM Type</target>
|
||||
<note>DM selector for seeing either DMs or message requests, which are messages that have not been responded to yet. DM is the English abbreviation for Direct Message.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DMs" xml:space="preserve">
|
||||
<source>DMs</source>
|
||||
<target>DMs</target>
|
||||
<note>Navigation title for DMs view, where DM is the English abbreviation for Direct Message.
|
||||
Navigation title for view of DMs, where DM is an English abbreviation for Direct Message.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Damus" xml:space="preserve">
|
||||
<source>Damus</source>
|
||||
@@ -342,21 +336,16 @@
|
||||
<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 id="Edit participants" xml:space="preserve">
|
||||
<source>Edit participants</source>
|
||||
<target>Edit participants</target>
|
||||
<note>Text indicating that the view is used for editing which participants are replied to in a note.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypted" xml:space="preserve">
|
||||
<source>Encrypted</source>
|
||||
<target>Encrypted</target>
|
||||
<note>Heading indicating that this application keeps private messaging end-to-end encrypted.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypted DMs" xml:space="preserve">
|
||||
<source>Encrypted DMs</source>
|
||||
<target>Encrypted DMs</target>
|
||||
<note>Navigation title for view of encrypted DMs, where DM is an English abbreviation for Direct Message.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter your account key to login:" xml:space="preserve">
|
||||
<source>Enter your account key to login:</source>
|
||||
<target>Enter your account key to login:</target>
|
||||
@@ -428,6 +417,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 +445,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>
|
||||
@@ -523,13 +518,13 @@ Part of a larger sentence to describe how many profiles a user is following.</no
|
||||
<trans-unit id="Private Key" xml:space="preserve">
|
||||
<source>Private Key</source>
|
||||
<target>Private Key</target>
|
||||
<note>Label to indicate that the text below is the user's private key used by only the user themself as a secret to login to access their account.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="PrivateKey" xml:space="preserve">
|
||||
<source>PrivateKey</source>
|
||||
<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 +550,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 +568,12 @@ 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="Remove all" xml:space="preserve">
|
||||
<source>Remove all</source>
|
||||
<target>Remove all</target>
|
||||
<note>Button label to remove all participants from a note reply.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Reply to self" xml:space="preserve">
|
||||
<source>Reply to self</source>
|
||||
@@ -586,11 +590,32 @@ 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="Requests" xml:space="preserve">
|
||||
<source>Requests</source>
|
||||
<target>Requests</target>
|
||||
<note>Picker option for DM selector for seeing only message requests (DMs that someone else sent the user which has not been responded to yet). DM is the English abbreviation for Direct Message.</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 +669,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 +687,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 +754,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 +804,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 +844,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 +864,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 +899,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 +907,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 +916,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 +992,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 +1006,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>
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
/* Bundle name */
|
||||
"CFBundleName" = "damus";
|
||||
/* Privacy - Photo Library Additions Usage Description */
|
||||
"NSPhotoLibraryAddUsageDescription" = "\"Granting Damus access to your photo library allows you to save photos.";
|
||||
"NSPhotoLibraryAddUsageDescription" = "Granting Damus access to your photos allows you to save images.";
|
||||
|
||||
Binary file not shown.
@@ -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>
|
||||
|
||||
Binary file not shown.
@@ -1,60 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>replying_to_one_and_others</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>Replying to %@%#@OTHERS@</string>
|
||||
<key>OTHERS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>zero</key>
|
||||
<string></string>
|
||||
<key>one</key>
|
||||
<string> & 1 other</string>
|
||||
<key>other</key>
|
||||
<string> & %d others</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>replying_to_two_and_others</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>Replying to %@, %@%#@OTHERS@</string>
|
||||
<key>OTHERS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>zero</key>
|
||||
<string></string>
|
||||
<key>one</key>
|
||||
<string> & 1 other</string>
|
||||
<key>other</key>
|
||||
<string> & %d others</string>
|
||||
</dict>
|
||||
</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>zero</key>
|
||||
<string>0 other notes</string>
|
||||
<key>one</key>
|
||||
<string>1 other note</string>
|
||||
<key>other</key>
|
||||
<string>%d other notes</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"developmentRegion" : "en-US",
|
||||
"project" : "damus.xcodeproj",
|
||||
"targetLocale" : "es-419",
|
||||
"toolInfo" : {
|
||||
"toolBuildNumber" : "14C18",
|
||||
"toolID" : "com.apple.dt.xcode",
|
||||
"toolName" : "Xcode",
|
||||
"toolVersion" : "14.2"
|
||||
},
|
||||
"version" : "1.0"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
1234
damus Localizations/fr_FR.xcloc/Localized Contents/fr_FR.xliff
Normal file
1234
damus Localizations/fr_FR.xcloc/Localized Contents/fr_FR.xliff
Normal file
File diff suppressed because it is too large
Load Diff
1234
damus Localizations/tr_TR.xcloc/Localized Contents/tr_TR.xliff
Normal file
1234
damus Localizations/tr_TR.xcloc/Localized Contents/tr_TR.xliff
Normal file
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,10 @@ static inline int is_whitespace(char c) {
|
||||
return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r';
|
||||
}
|
||||
|
||||
static inline int is_boundary(char c) {
|
||||
return !isalnum(c);
|
||||
}
|
||||
|
||||
static void make_cursor(struct cursor *c, const u8 *content, size_t len)
|
||||
{
|
||||
c->start = content;
|
||||
@@ -29,18 +33,35 @@ static void make_cursor(struct cursor *c, const u8 *content, size_t len)
|
||||
c->p = content;
|
||||
}
|
||||
|
||||
static int consume_until_whitespace(struct cursor *cur, int or_end) {
|
||||
static int consume_until_boundary(struct cursor *cur) {
|
||||
char c;
|
||||
|
||||
while (cur->p < cur->end) {
|
||||
c = *cur->p;
|
||||
|
||||
if (is_whitespace(c))
|
||||
if (is_boundary(c))
|
||||
return 1;
|
||||
|
||||
cur->p++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int consume_until_whitespace(struct cursor *cur, int or_end) {
|
||||
char c;
|
||||
bool consumedAtLeastOne = false;
|
||||
|
||||
while (cur->p < cur->end) {
|
||||
c = *cur->p;
|
||||
|
||||
if (is_whitespace(c) && consumedAtLeastOne)
|
||||
return 1;
|
||||
|
||||
cur->p++;
|
||||
consumedAtLeastOne = true;
|
||||
}
|
||||
|
||||
return or_end;
|
||||
}
|
||||
|
||||
@@ -145,7 +166,7 @@ static int parse_hashtag(struct cursor *cur, struct block *block) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
consume_until_whitespace(cur, 1);
|
||||
consume_until_boundary(cur);
|
||||
|
||||
block->type = BLOCK_HASHTAG;
|
||||
block->block.str.start = (const char*)(start + 1);
|
||||
|
||||
@@ -12,6 +12,11 @@
|
||||
3169CAED294FCCFC00EE4006 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3169CAEC294FCCFC00EE4006 /* Constants.swift */; };
|
||||
31D2E847295218AF006D67F8 /* Shimmer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D2E846295218AF006D67F8 /* Shimmer.swift */; };
|
||||
3A4325A82961E11400BFCD9D /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 3A4325AA2961E11400BFCD9D /* Localizable.stringsdict */; };
|
||||
3AA247FD297E3CFF0090C62D /* RepostsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA247FC297E3CFF0090C62D /* RepostsModel.swift */; };
|
||||
3AA247FF297E3D900090C62D /* RepostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA247FE297E3D900090C62D /* RepostsView.swift */; };
|
||||
3AA24802297E3DC20090C62D /* RepostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA24801297E3DC20090C62D /* RepostView.swift */; };
|
||||
3ACB685C297633BC00C46468 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3ACB685A297633BC00C46468 /* InfoPlist.strings */; };
|
||||
3ACB685F297633BC00C46468 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3ACB685D297633BC00C46468 /* Localizable.strings */; };
|
||||
3ACBCB78295FE5C70037388A /* TimeAgoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ACBCB77295FE5C70037388A /* TimeAgoTests.swift */; };
|
||||
4C06670128FC7C5900038D2A /* RelayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C06670028FC7C5900038D2A /* RelayView.swift */; };
|
||||
4C06670428FC7EC500038D2A /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 4C06670328FC7EC500038D2A /* Kingfisher */; };
|
||||
@@ -122,6 +127,15 @@
|
||||
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 */; };
|
||||
4CBCA930297DB57F00EC6B2F /* WebsiteLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CBCA92F297DB57F00EC6B2F /* WebsiteLink.swift */; };
|
||||
4CC7AAEB297F0AEC00430951 /* BuilderEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC7AAEA297F0AEC00430951 /* BuilderEventView.swift */; };
|
||||
4CC7AAED297F0B9E00430951 /* Highlight.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC7AAEC297F0B9E00430951 /* Highlight.swift */; };
|
||||
4CC7AAF0297F11C700430951 /* SelectedEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC7AAEF297F11C700430951 /* SelectedEventView.swift */; };
|
||||
4CC7AAF2297F129C00430951 /* EmbeddedEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC7AAF1297F129C00430951 /* EmbeddedEventView.swift */; };
|
||||
4CC7AAF4297F18B400430951 /* ReplyDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC7AAF3297F18B400430951 /* ReplyDescription.swift */; };
|
||||
4CC7AAF6297F1A6A00430951 /* EventBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC7AAF5297F1A6A00430951 /* EventBody.swift */; };
|
||||
4CC7AAF8297F1CEE00430951 /* EventProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC7AAF7297F1CEE00430951 /* EventProfile.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 */; };
|
||||
@@ -144,15 +158,21 @@
|
||||
4CEE2AF9280B2EAC00AB5EEF /* PowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2AF8280B2EAC00AB5EEF /* PowView.swift */; };
|
||||
4CEE2B02280B39E800AB5EEF /* EventActionBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2B01280B39E800AB5EEF /* EventActionBar.swift */; };
|
||||
4FE60CDD295E1C5E00105A1F /* Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE60CDC295E1C5E00105A1F /* Wallet.swift */; };
|
||||
6439E014296790CF0020672B /* ProfileZoomView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6439E013296790CF0020672B /* ProfileZoomView.swift */; };
|
||||
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 */; };
|
||||
E990020F2955F837003BBC5A /* EditMetadataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E990020E2955F837003BBC5A /* EditMetadataView.swift */; };
|
||||
E9E4ED0B295867B900DD7078 /* ThreadV2View.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E4ED0A295867B900DD7078 /* ThreadV2View.swift */; };
|
||||
F7F0BA25297892BD009531F3 /* SwipeToDismiss.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F0BA24297892BD009531F3 /* SwipeToDismiss.swift */; };
|
||||
F7F0BA272978E54D009531F3 /* ParicipantsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F0BA262978E54D009531F3 /* ParicipantsView.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -178,8 +198,25 @@
|
||||
3169CAEC294FCCFC00EE4006 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Constants.swift; path = damus/Util/Constants.swift; sourceTree = SOURCE_ROOT; };
|
||||
31D2E846295218AF006D67F8 /* Shimmer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shimmer.swift; sourceTree = "<group>"; };
|
||||
3A2B8B0A296A8982009CC16D /* en-US */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "en-US"; path = "en-US.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
|
||||
3A4F3320297CCFEE004B5F72 /* fr-FR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "fr-FR"; path = "fr-FR.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
||||
3A4F3321297CCFEE004B5F72 /* fr-FR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "fr-FR"; path = "fr-FR.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
3A4F3322297CCFEE004B5F72 /* fr-FR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "fr-FR"; path = "fr-FR.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
|
||||
3A5C4575296A879E0032D398 /* es-419 */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "es-419"; path = "es-419.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
|
||||
3A5EA10F297CCF6C00569477 /* de-AT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "de-AT"; path = "de-AT.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
||||
3A5EA110297CCF6C00569477 /* de-AT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "de-AT"; path = "de-AT.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
3A5EA111297CCF6C00569477 /* de-AT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "de-AT"; path = "de-AT.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
|
||||
3AA247FC297E3CFF0090C62D /* RepostsModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepostsModel.swift; sourceTree = "<group>"; };
|
||||
3AA247FE297E3D900090C62D /* RepostsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepostsView.swift; sourceTree = "<group>"; };
|
||||
3AA24801297E3DC20090C62D /* RepostView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepostView.swift; sourceTree = "<group>"; };
|
||||
3ACB685B297633BC00C46468 /* es-419 */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-419"; path = "es-419.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
||||
3ACB685E297633BC00C46468 /* es-419 */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-419"; path = "es-419.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
3ACBCB77295FE5C70037388A /* TimeAgoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeAgoTests.swift; sourceTree = "<group>"; };
|
||||
3AEABD20297CCFA8003F2975 /* de-DE */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "de-DE"; path = "de-DE.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
||||
3AEABD21297CCFA8003F2975 /* de-DE */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "de-DE"; path = "de-DE.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
3AEABD22297CCFA8003F2975 /* de-DE */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "de-DE"; path = "de-DE.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
|
||||
3AEB8003297CCEA800713A25 /* tr-TR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "tr-TR"; path = "tr-TR.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
||||
3AEB8004297CCEA800713A25 /* tr-TR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "tr-TR"; path = "tr-TR.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
3AEB8005297CCEA900713A25 /* tr-TR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "tr-TR"; path = "tr-TR.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
|
||||
4C06670028FC7C5900038D2A /* RelayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayView.swift; sourceTree = "<group>"; };
|
||||
4C06670528FCB08600038D2A /* ImageCarousel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCarousel.swift; sourceTree = "<group>"; };
|
||||
4C06670828FDE64700038D2A /* damus-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "damus-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
@@ -321,6 +358,15 @@
|
||||
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>"; };
|
||||
4CBCA92F297DB57F00EC6B2F /* WebsiteLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebsiteLink.swift; sourceTree = "<group>"; };
|
||||
4CC7AAEA297F0AEC00430951 /* BuilderEventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuilderEventView.swift; sourceTree = "<group>"; };
|
||||
4CC7AAEC297F0B9E00430951 /* Highlight.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Highlight.swift; sourceTree = "<group>"; };
|
||||
4CC7AAEF297F11C700430951 /* SelectedEventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectedEventView.swift; sourceTree = "<group>"; };
|
||||
4CC7AAF1297F129C00430951 /* EmbeddedEventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmbeddedEventView.swift; sourceTree = "<group>"; };
|
||||
4CC7AAF3297F18B400430951 /* ReplyDescription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplyDescription.swift; sourceTree = "<group>"; };
|
||||
4CC7AAF5297F1A6A00430951 /* EventBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventBody.swift; sourceTree = "<group>"; };
|
||||
4CC7AAF7297F1CEE00430951 /* EventProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventProfile.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>"; };
|
||||
@@ -346,14 +392,18 @@
|
||||
4CEE2AF8280B2EAC00AB5EEF /* PowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PowView.swift; sourceTree = "<group>"; };
|
||||
4CEE2B01280B39E800AB5EEF /* EventActionBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventActionBar.swift; sourceTree = "<group>"; };
|
||||
4FE60CDC295E1C5E00105A1F /* Wallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wallet.swift; sourceTree = "<group>"; };
|
||||
6439E013296790CF0020672B /* ProfileZoomView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileZoomView.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>"; };
|
||||
E990020E2955F837003BBC5A /* EditMetadataView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditMetadataView.swift; sourceTree = "<group>"; };
|
||||
E9E4ED0A295867B900DD7078 /* ThreadV2View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadV2View.swift; sourceTree = "<group>"; };
|
||||
F7F0BA24297892BD009531F3 /* SwipeToDismiss.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeToDismiss.swift; sourceTree = "<group>"; };
|
||||
F7F0BA262978E54D009531F3 /* ParicipantsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParicipantsView.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -361,6 +411,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 */,
|
||||
@@ -393,6 +445,14 @@
|
||||
path = "Empty Views";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3AA24800297E3DAE0090C62D /* Reposts */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3AA24801297E3DC20090C62D /* RepostView.swift */,
|
||||
);
|
||||
path = Reposts;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4C06670728FDE62900038D2A /* damus-c */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -450,6 +510,7 @@
|
||||
4C0A3F8D280F63FF000448DE /* Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3AA247FC297E3CFF0090C62D /* RepostsModel.swift */,
|
||||
4C0A3F8E280F640A000448DE /* ThreadModel.swift */,
|
||||
4C0A3F92280F66F5000448DE /* ReplyMap.swift */,
|
||||
4C3BEFD12819DB9B00B3DE84 /* ProfileModel.swift */,
|
||||
@@ -480,6 +541,7 @@
|
||||
BA693073295D649800ADDB87 /* UserSettingsStore.swift */,
|
||||
4FE60CDC295E1C5E00105A1F /* Wallet.swift */,
|
||||
4CB88392296F798300DC99E7 /* ReactionsModel.swift */,
|
||||
7C45AE70297353390031D7BC /* KFImageModel.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
@@ -487,6 +549,8 @@
|
||||
4C75EFA227FA576C0006080F /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4CC7AAEE297F11B300430951 /* Events */,
|
||||
3AA24800297E3DAE0090C62D /* Reposts */,
|
||||
4CB88394296F7F8100DC99E7 /* Reactions */,
|
||||
4CB88387296AF97C00DC99E7 /* ActionBar */,
|
||||
4CE4F9E228528C5200C00DD9 /* AddRelayView.swift */,
|
||||
@@ -501,8 +565,8 @@
|
||||
4C216F33286F5ACD00040376 /* DMView.swift */,
|
||||
E990020E2955F837003BBC5A /* EditMetadataView.swift */,
|
||||
3169CAE4294E699400EE4006 /* Empty Views */,
|
||||
4CEE2AF0280B216B00AB5EEF /* EventDetailView.swift */,
|
||||
4C75EFB82804A2740006080F /* EventView.swift */,
|
||||
4CEE2AF0280B216B00AB5EEF /* EventDetailView.swift */,
|
||||
4C3AC79E2833115300E1F516 /* FollowButtonView.swift */,
|
||||
4C3AC79C2833036D00E1F516 /* FollowingView.swift */,
|
||||
4C90BD17283A9EE5008EE7EF /* LoginView.swift */,
|
||||
@@ -521,6 +585,7 @@
|
||||
4C06670028FC7C5900038D2A /* RelayView.swift */,
|
||||
4C0A3F94280F6C78000448DE /* ReplyQuoteView.swift */,
|
||||
4CACA9D4280C31E100D9BBE8 /* ReplyView.swift */,
|
||||
F7F0BA262978E54D009531F3 /* ParicipantsView.swift */,
|
||||
4C285C8D28399BFD008A31F1 /* SaveKeysView.swift */,
|
||||
4C3AC7A628369BA200E1F516 /* SearchHomeView.swift */,
|
||||
4C5C7E69284EDE2E00A22DF5 /* SearchResultsView.swift */,
|
||||
@@ -534,6 +599,8 @@
|
||||
647D9A8C2968520300A295DE /* SideMenuView.swift */,
|
||||
9609F057296E220800069BF3 /* BannerImageView.swift */,
|
||||
4CB8838E296F781C00DC99E7 /* ReactionsView.swift */,
|
||||
6439E013296790CF0020672B /* ProfileZoomView.swift */,
|
||||
3AA247FE297E3D900090C62D /* RepostsView.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
@@ -596,6 +663,19 @@
|
||||
path = Reactions;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4CC7AAEE297F11B300430951 /* Events */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4CC7AAEF297F11C700430951 /* SelectedEventView.swift */,
|
||||
4CC7AAF1297F129C00430951 /* EmbeddedEventView.swift */,
|
||||
4CC7AAF3297F18B400430951 /* ReplyDescription.swift */,
|
||||
4CC7AAF5297F1A6A00430951 /* EventBody.swift */,
|
||||
4CC7AAEA297F0AEC00430951 /* BuilderEventView.swift */,
|
||||
4CC7AAF7297F1CEE00430951 /* EventProfile.swift */,
|
||||
);
|
||||
path = Events;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4CE4F9DF285287A000C00DD9 /* Components */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -607,6 +687,8 @@
|
||||
4C3EA67E28FFC01D00C48A62 /* InvoiceView.swift */,
|
||||
4CB8838A296F6E1E00DC99E7 /* NIP05Badge.swift */,
|
||||
4CB8838C296F710400DC99E7 /* Reposted.swift */,
|
||||
4CBCA92F297DB57F00EC6B2F /* WebsiteLink.swift */,
|
||||
4CC7AAEC297F0B9E00430951 /* Highlight.swift */,
|
||||
);
|
||||
path = Components;
|
||||
sourceTree = "<group>";
|
||||
@@ -636,12 +718,15 @@
|
||||
4CE6DEE527F7A08100C66700 /* damus */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F7F0BA23297892AE009531F3 /* Modifiers */,
|
||||
4C4A3A5A288A1B2200453788 /* damus.entitlements */,
|
||||
4CE4F9DF285287A000C00DD9 /* Components */,
|
||||
4C7FF7D628233637009601DB /* Util */,
|
||||
4C0A3F8D280F63FF000448DE /* Models */,
|
||||
4C75EFAB28049CC80006080F /* Nostr */,
|
||||
4C75EFA72804823E0006080F /* Info.plist */,
|
||||
3ACB685D297633BC00C46468 /* Localizable.strings */,
|
||||
3ACB685A297633BC00C46468 /* InfoPlist.strings */,
|
||||
4C75EFA227FA576C0006080F /* Views */,
|
||||
4CE6DEE627F7A08100C66700 /* damusApp.swift */,
|
||||
4CE6DEE827F7A08100C66700 /* ContentView.swift */,
|
||||
@@ -670,6 +755,7 @@
|
||||
4CE6DEF727F7A08200C66700 /* damusTests.swift */,
|
||||
4C3EA67A28FF7B3900C48A62 /* InvoiceTests.swift */,
|
||||
3ACBCB77295FE5C70037388A /* TimeAgoTests.swift */,
|
||||
4CB88399297322D200DC99E7 /* DMTests.swift */,
|
||||
);
|
||||
path = damusTests;
|
||||
sourceTree = "<group>";
|
||||
@@ -691,6 +777,14 @@
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F7F0BA23297892AE009531F3 /* Modifiers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F7F0BA24297892BD009531F3 /* SwipeToDismiss.swift */,
|
||||
);
|
||||
path = Modifiers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@@ -712,6 +806,8 @@
|
||||
4C649880286E0EE300EAE2B3 /* secp256k1 */,
|
||||
4C06670328FC7EC500038D2A /* Kingfisher */,
|
||||
6C7DE41E2955169800E66263 /* Vault */,
|
||||
7C45AE6C297352F90031D7BC /* SVGKit */,
|
||||
7C45AE6E297352F90031D7BC /* SVGKitSwift */,
|
||||
);
|
||||
productName = damus;
|
||||
productReference = 4CE6DEE327F7A08100C66700 /* damus.app */;
|
||||
@@ -785,6 +881,10 @@
|
||||
Base,
|
||||
"es-419",
|
||||
"en-US",
|
||||
"de-AT",
|
||||
"de-DE",
|
||||
"tr-TR",
|
||||
"fr-FR",
|
||||
);
|
||||
mainGroup = 4CE6DEDA27F7A08100C66700;
|
||||
packageReferences = (
|
||||
@@ -792,6 +892,7 @@
|
||||
4C64987F286E0EE300EAE2B3 /* XCRemoteSwiftPackageReference "secp256k1" */,
|
||||
4C06670228FC7EC500038D2A /* XCRemoteSwiftPackageReference "Kingfisher" */,
|
||||
6C7DE41D2955169800E66263 /* XCRemoteSwiftPackageReference "Vault" */,
|
||||
7C45AE6B297352F90031D7BC /* XCRemoteSwiftPackageReference "SVGKit" */,
|
||||
);
|
||||
productRefGroup = 4CE6DEE427F7A08100C66700 /* Products */;
|
||||
projectDirPath = "";
|
||||
@@ -809,7 +910,9 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
3ACB685F297633BC00C46468 /* Localizable.strings in Resources */,
|
||||
4CE6DEEE27F7A08200C66700 /* Preview Assets.xcassets in Resources */,
|
||||
3ACB685C297633BC00C46468 /* InfoPlist.strings in Resources */,
|
||||
4CE6DEEB27F7A08200C66700 /* Assets.xcassets in Resources */,
|
||||
3A4325A82961E11400BFCD9D /* Localizable.stringsdict in Resources */,
|
||||
);
|
||||
@@ -856,8 +959,10 @@
|
||||
4C75EFAD28049CFB0006080F /* PostButton.swift in Sources */,
|
||||
4CB55EF5295E679D007FD187 /* UserRelaysView.swift in Sources */,
|
||||
4C363AA228296A7E006E126D /* SearchView.swift in Sources */,
|
||||
4CC7AAED297F0B9E00430951 /* Highlight.swift in Sources */,
|
||||
4C285C8A2838B985008A31F1 /* ProfilePictureSelector.swift in Sources */,
|
||||
4C75EFB92804A2740006080F /* EventView.swift in Sources */,
|
||||
3AA247FD297E3CFF0090C62D /* RepostsModel.swift in Sources */,
|
||||
4C7FF7D52823313F009601DB /* Mentions.swift in Sources */,
|
||||
4C633350283D40E500B1C9C3 /* HomeModel.swift in Sources */,
|
||||
4C987B57283FD07F0042CE38 /* FollowersModel.swift in Sources */,
|
||||
@@ -865,12 +970,14 @@
|
||||
4C0A3F8C280F5FCA000448DE /* ChatroomView.swift in Sources */,
|
||||
4C477C9E282C3A4800033AA3 /* TipCounter.swift in Sources */,
|
||||
647D9A8D2968520300A295DE /* SideMenuView.swift in Sources */,
|
||||
F7F0BA272978E54D009531F3 /* ParicipantsView.swift in Sources */,
|
||||
4C0A3F91280F6528000448DE /* ChatView.swift in Sources */,
|
||||
4C216F362870A9A700040376 /* InputDismissKeyboard.swift in Sources */,
|
||||
4C216F382871EDE300040376 /* DirectMessageModel.swift in Sources */,
|
||||
4C75EFA627FF87A20006080F /* Nostr.swift in Sources */,
|
||||
4CE4F9DE2852768D00C00DD9 /* ConfigView.swift in Sources */,
|
||||
4C285C8E28399BFE008A31F1 /* SaveKeysView.swift in Sources */,
|
||||
F7F0BA25297892BD009531F3 /* SwipeToDismiss.swift in Sources */,
|
||||
4CB8838F296F781C00DC99E7 /* ReactionsView.swift in Sources */,
|
||||
4C649844285A952100EAE2B3 /* LocalUserConfig.swift in Sources */,
|
||||
4C75EFB328049D640006080F /* NostrEvent.swift in Sources */,
|
||||
@@ -886,17 +993,22 @@
|
||||
4C3BEFDC281DCE6100B3DE84 /* Liked.swift in Sources */,
|
||||
4C75EFB128049D510006080F /* NostrResponse.swift in Sources */,
|
||||
4CEE2AF7280B2DEA00AB5EEF /* ProfileName.swift in Sources */,
|
||||
4CC7AAEB297F0AEC00430951 /* BuilderEventView.swift in Sources */,
|
||||
31D2E847295218AF006D67F8 /* Shimmer.swift in Sources */,
|
||||
4C285C8228385570008A31F1 /* CarouselView.swift in Sources */,
|
||||
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 */,
|
||||
4CC7AAF2297F129C00430951 /* EmbeddedEventView.swift in Sources */,
|
||||
4C3AC79F2833115300E1F516 /* FollowButtonView.swift in Sources */,
|
||||
4C3BEFD22819DB9B00B3DE84 /* ProfileModel.swift in Sources */,
|
||||
4C0A3F93280F66F5000448DE /* ReplyMap.swift in Sources */,
|
||||
BAB68BED29543FA3007BA466 /* SelectWalletView.swift in Sources */,
|
||||
3169CAE6294E69C000EE4006 /* EmptyTimelineView.swift in Sources */,
|
||||
4CC7AAF0297F11C700430951 /* SelectedEventView.swift in Sources */,
|
||||
4CC7AAF8297F1CEE00430951 /* EventProfile.swift in Sources */,
|
||||
64FBD06F296255C400D9D3B2 /* Theme.swift in Sources */,
|
||||
4C3EA64928FF597700C48A62 /* bech32.c in Sources */,
|
||||
4C90BD162839DB54008EE7EF /* NostrMetadata.swift in Sources */,
|
||||
@@ -917,8 +1029,10 @@
|
||||
4C75EFAF28049D350006080F /* NostrFilter.swift in Sources */,
|
||||
4C3EA64C28FF59AC00C48A62 /* bech32_util.c in Sources */,
|
||||
4C363A9C282838B9006E126D /* EventRef.swift in Sources */,
|
||||
3AA24802297E3DC20090C62D /* RepostView.swift in Sources */,
|
||||
4CD7641B28A1641400B6928F /* EndBlock.swift in Sources */,
|
||||
4C3EA66528FF5F6800C48A62 /* mem.c in Sources */,
|
||||
4CBCA930297DB57F00EC6B2F /* WebsiteLink.swift in Sources */,
|
||||
4C3EA64128FF553900C48A62 /* hash_u5.c in Sources */,
|
||||
4C3EA64F28FF59F200C48A62 /* tal.c in Sources */,
|
||||
4CB88393296F798300DC99E7 /* ReactionsModel.swift in Sources */,
|
||||
@@ -927,10 +1041,12 @@
|
||||
4C5F9114283D694D0052CD1C /* FollowTarget.swift in Sources */,
|
||||
4CB8838629656C8B00DC99E7 /* NIP05.swift in Sources */,
|
||||
4C5C7E6A284EDE2E00A22DF5 /* SearchResultsView.swift in Sources */,
|
||||
6439E014296790CF0020672B /* ProfileZoomView.swift in Sources */,
|
||||
4CE6DF1627F8DEBF00C66700 /* RelayConnection.swift in Sources */,
|
||||
4C3BEFD6281D995700B3DE84 /* ActionBarModel.swift in Sources */,
|
||||
4C363AA428296DEE006E126D /* SearchModel.swift in Sources */,
|
||||
4CEE2AF3280B25C500AB5EEF /* ProfilePicView.swift in Sources */,
|
||||
4CC7AAF6297F1A6A00430951 /* EventBody.swift in Sources */,
|
||||
4CEE2AF9280B2EAC00AB5EEF /* PowView.swift in Sources */,
|
||||
3165648B295B70D500C64604 /* LinkView.swift in Sources */,
|
||||
4C3BEFD42819DE8F00B3DE84 /* NostrKind.swift in Sources */,
|
||||
@@ -959,7 +1075,9 @@
|
||||
4C0A3F97280F8E02000448DE /* ThreadView.swift in Sources */,
|
||||
4C06670B28FDE64700038D2A /* damus.c in Sources */,
|
||||
4FE60CDD295E1C5E00105A1F /* Wallet.swift in Sources */,
|
||||
3AA247FF297E3D900090C62D /* RepostsView.swift in Sources */,
|
||||
4C99737B28C92A9200E53835 /* ChatroomMetadata.swift in Sources */,
|
||||
4CC7AAF4297F18B400430951 /* ReplyDescription.swift in Sources */,
|
||||
4C75EFA427FA577B0006080F /* PostView.swift in Sources */,
|
||||
4C75EFB528049D790006080F /* Relay.swift in Sources */,
|
||||
4CEE2AF1280B216B00AB5EEF /* EventDetailView.swift in Sources */,
|
||||
@@ -977,6 +1095,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 */,
|
||||
@@ -1013,10 +1132,38 @@
|
||||
children = (
|
||||
3A5C4575296A879E0032D398 /* es-419 */,
|
||||
3A2B8B0A296A8982009CC16D /* en-US */,
|
||||
3A5EA111297CCF6C00569477 /* de-AT */,
|
||||
3AEABD22297CCFA8003F2975 /* de-DE */,
|
||||
3AEB8005297CCEA900713A25 /* tr-TR */,
|
||||
3A4F3322297CCFEE004B5F72 /* fr-FR */,
|
||||
);
|
||||
name = Localizable.stringsdict;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3ACB685A297633BC00C46468 /* InfoPlist.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
3ACB685B297633BC00C46468 /* es-419 */,
|
||||
3A5EA10F297CCF6C00569477 /* de-AT */,
|
||||
3AEABD20297CCFA8003F2975 /* de-DE */,
|
||||
3AEB8003297CCEA800713A25 /* tr-TR */,
|
||||
3A4F3320297CCFEE004B5F72 /* fr-FR */,
|
||||
);
|
||||
name = InfoPlist.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3ACB685D297633BC00C46468 /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
3ACB685E297633BC00C46468 /* es-419 */,
|
||||
3A5EA110297CCF6C00569477 /* de-AT */,
|
||||
3AEABD21297CCFA8003F2975 /* de-DE */,
|
||||
3AEB8004297CCEA800713A25 /* tr-TR */,
|
||||
3A4F3321297CCFEE004B5F72 /* fr-FR */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
@@ -1148,7 +1295,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = damus/damus.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 6;
|
||||
CURRENT_PROJECT_VERSION = 9;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"damus/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = XK7H4JAB3D;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -1156,6 +1303,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 photos allows you to save images.";
|
||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||
@@ -1188,7 +1336,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = damus/damus.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 6;
|
||||
CURRENT_PROJECT_VERSION = 9;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"damus/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = XK7H4JAB3D;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -1196,6 +1344,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 photos allows you to save images.";
|
||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||
@@ -1369,6 +1518,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 */
|
||||
@@ -1392,6 +1549,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",
|
||||
|
||||
39
damus/Components/Highlight.swift
Normal file
39
damus/Components/Highlight.swift
Normal file
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// Highlight.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-01-23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
|
||||
enum Highlight {
|
||||
case none
|
||||
case main
|
||||
case reply
|
||||
case custom(Color, Float)
|
||||
|
||||
var is_main: Bool {
|
||||
if case .main = self {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var is_none: Bool {
|
||||
if case .none = self {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var is_replied_to: Bool {
|
||||
switch self {
|
||||
case .reply: return true
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,14 +12,14 @@ import Kingfisher
|
||||
struct ShareSheet: UIViewControllerRepresentable {
|
||||
typealias Callback = (_ activityType: UIActivity.ActivityType?, _ completed: Bool, _ returnedItems: [Any]?, _ error: Error?) -> Void
|
||||
|
||||
let activityItems: [URL]
|
||||
let activityItems: [URL?]
|
||||
let callback: Callback? = nil
|
||||
let applicationActivities: [UIActivity]? = nil
|
||||
let excludedActivityTypes: [UIActivity.ActivityType]? = nil
|
||||
|
||||
func makeUIViewController(context: Context) -> UIActivityViewController {
|
||||
let controller = UIActivityViewController(
|
||||
activityItems: activityItems,
|
||||
activityItems: activityItems as [Any],
|
||||
applicationActivities: applicationActivities)
|
||||
controller.excludedActivityTypes = excludedActivityTypes
|
||||
controller.completionWithItemsHandler = callback
|
||||
@@ -32,7 +32,7 @@ struct ShareSheet: UIViewControllerRepresentable {
|
||||
}
|
||||
|
||||
struct ImageContextMenuModifier: ViewModifier {
|
||||
let url: URL
|
||||
let url: URL?
|
||||
let image: UIImage?
|
||||
@Binding var showShareSheet: Bool
|
||||
|
||||
@@ -64,8 +64,21 @@ struct ImageContextMenuModifier: ViewModifier {
|
||||
}
|
||||
}
|
||||
|
||||
struct ImageViewer: View {
|
||||
let urls: [URL]
|
||||
private struct ImageContainerView: View {
|
||||
|
||||
@ObservedObject var imageModel: KFImageModel
|
||||
|
||||
@State private var image: UIImage?
|
||||
@State private var showShareSheet = false
|
||||
|
||||
init(url: URL?) {
|
||||
self.imageModel = KFImageModel(
|
||||
url: url,
|
||||
fallbackUrl: nil,
|
||||
maxByteSize: 2000000, // 2 MB
|
||||
downsampleSize: CGSize(width: 400, height: 400)
|
||||
)
|
||||
}
|
||||
|
||||
private struct ImageHandler: ImageModifier {
|
||||
@Binding var handler: UIImage?
|
||||
@@ -75,45 +88,178 @@ struct ImageViewer: View {
|
||||
return image
|
||||
}
|
||||
}
|
||||
|
||||
@State private var image: UIImage?
|
||||
@State private var showShareSheet = false
|
||||
|
||||
func onShared(completed: Bool) -> Void {
|
||||
if (completed) {
|
||||
showShareSheet = false
|
||||
var body: some View {
|
||||
|
||||
KFAnimatedImage(imageModel.url)
|
||||
.callbackQueue(.dispatch(.global(qos: .background)))
|
||||
.processingQueue(.dispatch(.global(qos: .background)))
|
||||
.cacheOriginalImage()
|
||||
.configure { view in
|
||||
view.framePreloadCount = 1
|
||||
}
|
||||
.scaleFactor(UIScreen.main.scale)
|
||||
.loadDiskFileSynchronously()
|
||||
.fade(duration: 0.1)
|
||||
.imageModifier(ImageHandler(handler: $image))
|
||||
.onFailure { _ in
|
||||
imageModel.downloadFailed()
|
||||
}
|
||||
.id(imageModel.refreshID)
|
||||
.clipped()
|
||||
.modifier(ImageContextMenuModifier(url: imageModel.url, image: image, showShareSheet: $showShareSheet))
|
||||
.sheet(isPresented: $showShareSheet) {
|
||||
ShareSheet(activityItems: [imageModel.url])
|
||||
}
|
||||
|
||||
// TODO: Update ImageCarousel with serializer and processor
|
||||
// .serialize(by: imageModel.serializer)
|
||||
// .setProcessor(imageModel.processor)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
struct ZoomableScrollView<Content: View>: UIViewRepresentable {
|
||||
|
||||
private var content: Content
|
||||
|
||||
init(@ViewBuilder content: () -> Content) {
|
||||
self.content = content()
|
||||
}
|
||||
|
||||
func makeUIView(context: Context) -> UIScrollView {
|
||||
let scrollView = UIScrollView()
|
||||
scrollView.delegate = context.coordinator
|
||||
scrollView.maximumZoomScale = 20
|
||||
scrollView.minimumZoomScale = 1
|
||||
scrollView.bouncesZoom = true
|
||||
scrollView.showsVerticalScrollIndicator = false
|
||||
scrollView.showsHorizontalScrollIndicator = false
|
||||
|
||||
let hostedView = context.coordinator.hostingController.view!
|
||||
hostedView.translatesAutoresizingMaskIntoConstraints = true
|
||||
hostedView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
hostedView.frame = scrollView.bounds
|
||||
hostedView.backgroundColor = .clear
|
||||
scrollView.addSubview(hostedView)
|
||||
|
||||
return scrollView
|
||||
}
|
||||
|
||||
func makeCoordinator() -> Coordinator {
|
||||
return Coordinator(hostingController: UIHostingController(rootView: self.content))
|
||||
}
|
||||
|
||||
func updateUIView(_ uiView: UIScrollView, context: Context) {
|
||||
context.coordinator.hostingController.rootView = self.content
|
||||
assert(context.coordinator.hostingController.view.superview == uiView)
|
||||
}
|
||||
|
||||
class Coordinator: NSObject, UIScrollViewDelegate {
|
||||
var hostingController: UIHostingController<Content>
|
||||
|
||||
init(hostingController: UIHostingController<Content>) {
|
||||
self.hostingController = hostingController
|
||||
}
|
||||
|
||||
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
|
||||
return hostingController.view
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ImageView: View {
|
||||
|
||||
let urls: [URL?]
|
||||
|
||||
@Environment(\.presentationMode) var presentationMode
|
||||
|
||||
@State private var selectedIndex = 0
|
||||
@State var showMenu = true
|
||||
|
||||
var navBarView: some View {
|
||||
VStack {
|
||||
HStack {
|
||||
Text(urls[selectedIndex]?.lastPathComponent ?? "")
|
||||
.bold()
|
||||
|
||||
Spacer()
|
||||
|
||||
Button(action: {
|
||||
presentationMode.wrappedValue.dismiss()
|
||||
}, label: {
|
||||
Image(systemName: "xmark")
|
||||
})
|
||||
}
|
||||
.padding()
|
||||
|
||||
Divider()
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
.background(.regularMaterial)
|
||||
}
|
||||
|
||||
var tabViewIndicator: some View {
|
||||
HStack(spacing: 10) {
|
||||
ForEach(urls.indices, id: \.self) { index in
|
||||
Capsule()
|
||||
.fill(index == selectedIndex ? Color(UIColor.label) : Color.secondary)
|
||||
.frame(width: 7, height: 7)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.background(.regularMaterial)
|
||||
.clipShape(Capsule())
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
TabView {
|
||||
ForEach(urls, id: \.absoluteString) { url in
|
||||
VStack{
|
||||
Text(url.lastPathComponent)
|
||||
|
||||
KFAnimatedImage(url)
|
||||
.configure { view in
|
||||
view.framePreloadCount = 3
|
||||
}
|
||||
.cacheOriginalImage()
|
||||
.imageModifier(ImageHandler(handler: $image))
|
||||
.loadDiskFileSynchronously()
|
||||
.scaleFactor(UIScreen.main.scale)
|
||||
.fade(duration: 0.1)
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.tabItem {
|
||||
Text(url.absoluteString)
|
||||
}
|
||||
.id(url.absoluteString)
|
||||
.modifier(ImageContextMenuModifier(url: url, image: image, showShareSheet: $showShareSheet))
|
||||
.sheet(isPresented: $showShareSheet) {
|
||||
ShareSheet(activityItems: [url])
|
||||
}
|
||||
|
||||
ZStack {
|
||||
Color(.systemBackground)
|
||||
.ignoresSafeArea()
|
||||
|
||||
TabView(selection: $selectedIndex) {
|
||||
ForEach(urls.indices, id: \.self) { index in
|
||||
ZoomableScrollView {
|
||||
ImageContainerView(url: urls[index])
|
||||
.aspectRatio(contentMode: .fit)
|
||||
}
|
||||
.ignoresSafeArea()
|
||||
.tag(index)
|
||||
.modifier(SwipeToDismissModifier(minDistance: 50, onDismiss: {
|
||||
presentationMode.wrappedValue.dismiss()
|
||||
}))
|
||||
}
|
||||
}
|
||||
.ignoresSafeArea()
|
||||
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
|
||||
.onChange(of: selectedIndex, perform: { _ in
|
||||
showMenu = true
|
||||
})
|
||||
.onTapGesture {
|
||||
showMenu.toggle()
|
||||
}
|
||||
.overlay(
|
||||
VStack {
|
||||
if showMenu {
|
||||
navBarView
|
||||
Spacer()
|
||||
|
||||
if (urls.count > 1) {
|
||||
tabViewIndicator
|
||||
}
|
||||
}
|
||||
}
|
||||
.animation(.easeInOut, value: showMenu)
|
||||
.padding(
|
||||
.bottom,
|
||||
UIApplication
|
||||
.shared
|
||||
.connectedScenes
|
||||
.flatMap { ($0 as? UIWindowScene)?.windows ?? [] }
|
||||
.first { $0.isKeyWindow }?.safeAreaInsets.bottom
|
||||
)
|
||||
)
|
||||
}
|
||||
.tabViewStyle(PageTabViewStyle())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,13 +276,15 @@ struct ImageCarousel: View {
|
||||
.foregroundColor(Color.clear)
|
||||
.overlay {
|
||||
KFAnimatedImage(url)
|
||||
.configure { view in
|
||||
view.framePreloadCount = 3
|
||||
}
|
||||
.callbackQueue(.dispatch(.global(qos: .background)))
|
||||
.processingQueue(.dispatch(.global(qos: .background)))
|
||||
.cacheOriginalImage()
|
||||
.loadDiskFileSynchronously()
|
||||
.scaleFactor(UIScreen.main.scale)
|
||||
.fade(duration: 0.1)
|
||||
.configure { view in
|
||||
view.framePreloadCount = 3
|
||||
}
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.tabItem {
|
||||
Text(url.absoluteString)
|
||||
@@ -151,8 +299,8 @@ struct ImageCarousel: View {
|
||||
}
|
||||
}
|
||||
.cornerRadius(10)
|
||||
.sheet(isPresented: $open_sheet) {
|
||||
ImageViewer(urls: urls)
|
||||
.fullScreenCover(isPresented: $open_sheet) {
|
||||
ImageView(urls: urls)
|
||||
}
|
||||
.frame(height: 200)
|
||||
.onTapGesture {
|
||||
@@ -164,6 +312,6 @@ struct ImageCarousel: View {
|
||||
|
||||
struct ImageCarousel_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ImageCarousel(urls: [URL(string: "https://jb55.com/red-me.jpg")!])
|
||||
ImageCarousel(urls: [URL(string: "https://jb55.com/red-me.jpg")!,URL(string: "https://jb55.com/red-me.jpg")!])
|
||||
}
|
||||
}
|
||||
|
||||
38
damus/Components/WebsiteLink.swift
Normal file
38
damus/Components/WebsiteLink.swift
Normal file
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// WebsiteLink.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-01-22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct WebsiteLink: View {
|
||||
let url: URL
|
||||
@Environment(\.openURL) var openURL
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
Image(systemName: "link")
|
||||
.foregroundColor(.gray)
|
||||
.font(.footnote)
|
||||
|
||||
Button(action: {
|
||||
openURL(url)
|
||||
}, label: {
|
||||
Text(link_text)
|
||||
.font(.footnote)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var link_text: String {
|
||||
url.host ?? url.absoluteString
|
||||
}
|
||||
}
|
||||
|
||||
struct WebsiteLink_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
WebsiteLink(url: URL(string: "https://jb55.com")!)
|
||||
}
|
||||
}
|
||||
@@ -93,17 +93,25 @@ struct ContentView: View {
|
||||
|
||||
var PostingTimelineView: some View {
|
||||
VStack {
|
||||
TabView(selection: $filter_state) {
|
||||
contentTimelineView(filter: FilterState.posts.filter)
|
||||
.tag(FilterState.posts)
|
||||
.id(FilterState.posts)
|
||||
contentTimelineView(filter: FilterState.posts_and_replies.filter)
|
||||
.tag(FilterState.posts_and_replies)
|
||||
.id(FilterState.posts_and_replies)
|
||||
ZStack {
|
||||
TabView(selection: $filter_state) {
|
||||
contentTimelineView(filter: FilterState.posts.filter)
|
||||
.tag(FilterState.posts)
|
||||
.id(FilterState.posts)
|
||||
contentTimelineView(filter: FilterState.posts_and_replies.filter)
|
||||
.tag(FilterState.posts_and_replies)
|
||||
.id(FilterState.posts_and_replies)
|
||||
}
|
||||
.tabViewStyle(.page(indexDisplayMode: .never))
|
||||
|
||||
if privkey != nil {
|
||||
PostButtonContainer(userSettings: user_settings) {
|
||||
self.active_sheet = .post
|
||||
}
|
||||
}
|
||||
}
|
||||
.tabViewStyle(.page(indexDisplayMode: .never))
|
||||
}
|
||||
.safeAreaInset(edge: .top) {
|
||||
.safeAreaInset(edge: .top, spacing: 0) {
|
||||
VStack(spacing: 0) {
|
||||
FiltersView
|
||||
//.frame(maxWidth: 275)
|
||||
@@ -113,7 +121,6 @@ struct ContentView: View {
|
||||
}
|
||||
.background(colorScheme == .dark ? Color.black : Color.white)
|
||||
}
|
||||
.ignoresSafeArea(.keyboard)
|
||||
}
|
||||
|
||||
func contentTimelineView(filter: (@escaping (NostrEvent) -> Bool)) -> some View {
|
||||
@@ -121,11 +128,6 @@ struct ContentView: View {
|
||||
if let damus = self.damus_state {
|
||||
TimelineView(events: $home.events, loading: $home.loading, damus: damus, show_friend_icon: false, filter: filter)
|
||||
}
|
||||
if privkey != nil {
|
||||
PostButtonContainer(userSettings: user_settings) {
|
||||
self.active_sheet = .post
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,17 +174,27 @@ 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("DMs", comment: "Toolbar label for DMs view, where DM is the English abbreviation for Direct Message.")
|
||||
.bold()
|
||||
case .notifications:
|
||||
Text("Notifications", comment: "Toolbar label for Notifications view.")
|
||||
.bold()
|
||||
case .search:
|
||||
Text("Global", comment: "Toolbar label for Global view where posts from all connected relay servers appear.")
|
||||
.bold()
|
||||
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.")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.ignoresSafeArea(.keyboard)
|
||||
}
|
||||
|
||||
var MaybeSearchView: some View {
|
||||
@@ -229,11 +241,7 @@ struct ContentView: View {
|
||||
Button {
|
||||
isSideBarOpened.toggle()
|
||||
} label: {
|
||||
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>
|
||||
|
||||
@@ -22,8 +22,13 @@ struct DamusState {
|
||||
var pubkey: String {
|
||||
return keypair.pubkey
|
||||
}
|
||||
|
||||
var is_privkey_user: Bool {
|
||||
keypair.privkey != nil
|
||||
}
|
||||
|
||||
|
||||
static var empty: DamusState {
|
||||
return DamusState.init(pool: RelayPool(), keypair: Keypair(pubkey: "", privkey: ""), likes: EventCounter(our_pubkey: ""), boosts: EventCounter(our_pubkey: ""), contacts: Contacts(our_pubkey: ""), tips: TipCounter(our_pubkey: ""), profiles: Profiles(), dms: DirectMessagesModel(), previews: PreviewCache())
|
||||
return DamusState.init(pool: RelayPool(), keypair: Keypair(pubkey: "", privkey: ""), likes: EventCounter(our_pubkey: ""), boosts: EventCounter(our_pubkey: ""), contacts: Contacts(our_pubkey: ""), tips: TipCounter(our_pubkey: ""), profiles: Profiles(), dms: DirectMessagesModel(our_pubkey: ""), previews: PreviewCache())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,34 @@
|
||||
import Foundation
|
||||
|
||||
class DirectMessageModel: ObservableObject {
|
||||
@Published var events: [NostrEvent]
|
||||
|
||||
init(events: [NostrEvent]) {
|
||||
self.events = events
|
||||
@Published var events: [NostrEvent] {
|
||||
didSet {
|
||||
is_request = determine_is_request()
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
var is_request: Bool
|
||||
var our_pubkey: String
|
||||
|
||||
func determine_is_request() -> Bool {
|
||||
for event in events {
|
||||
if event.pubkey == our_pubkey {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
init(events: [NostrEvent], our_pubkey: String) {
|
||||
self.events = events
|
||||
self.is_request = false
|
||||
self.our_pubkey = our_pubkey
|
||||
}
|
||||
|
||||
init(our_pubkey: String) {
|
||||
self.events = []
|
||||
self.is_request = false
|
||||
self.our_pubkey = our_pubkey
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,13 +10,26 @@ import Foundation
|
||||
class DirectMessagesModel: ObservableObject {
|
||||
@Published var dms: [(String, DirectMessageModel)] = []
|
||||
@Published var loading: Bool = false
|
||||
let our_pubkey: String
|
||||
|
||||
init(our_pubkey: String) {
|
||||
self.our_pubkey = our_pubkey
|
||||
}
|
||||
|
||||
var message_requests: [(String, DirectMessageModel)] {
|
||||
return dms.filter { dm in dm.1.is_request }
|
||||
}
|
||||
|
||||
var friend_dms: [(String, DirectMessageModel)] {
|
||||
return dms.filter { dm in !dm.1.is_request }
|
||||
}
|
||||
|
||||
func lookup_or_create(_ pubkey: String) -> DirectMessageModel {
|
||||
if let dm = lookup(pubkey) {
|
||||
return dm
|
||||
}
|
||||
|
||||
let new = DirectMessageModel()
|
||||
let new = DirectMessageModel(our_pubkey: our_pubkey)
|
||||
dms.append((pubkey, new))
|
||||
return new
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -48,17 +48,19 @@ class HomeModel: ObservableObject {
|
||||
|
||||
@Published var new_events: NewEventsBits = NewEventsBits()
|
||||
@Published var notifications: [NostrEvent] = []
|
||||
@Published var dms: DirectMessagesModel = DirectMessagesModel()
|
||||
@Published var dms: DirectMessagesModel
|
||||
@Published var events: [NostrEvent] = []
|
||||
@Published var loading: Bool = false
|
||||
@Published var signal: SignalModel = SignalModel()
|
||||
|
||||
init() {
|
||||
self.damus_state = DamusState.empty
|
||||
self.dms = DirectMessagesModel(our_pubkey: damus_state.pubkey)
|
||||
}
|
||||
|
||||
init(damus_state: DamusState) {
|
||||
self.damus_state = damus_state
|
||||
self.dms = DirectMessagesModel(our_pubkey: damus_state.pubkey)
|
||||
}
|
||||
|
||||
var pool: RelayPool {
|
||||
@@ -347,24 +349,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 +392,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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -656,4 +616,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], our_pubkey: our_pubkey)
|
||||
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
|
||||
}
|
||||
|
||||
108
damus/Models/KFImageModel.swift
Normal file
108
damus/Models/KFImageModel.swift
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
77
damus/Models/RepostsModel.swift
Normal file
77
damus/Models/RepostsModel.swift
Normal file
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// RepostsModel.swift
|
||||
// damus
|
||||
//
|
||||
// Created by Terry Yiu on 1/22/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class RepostsModel: ObservableObject {
|
||||
let state: DamusState
|
||||
let target: String
|
||||
let sub_id: String
|
||||
let profiles_id: String
|
||||
|
||||
@Published var reposts: [NostrEvent]
|
||||
|
||||
init (state: DamusState, target: String) {
|
||||
self.state = state
|
||||
self.target = target
|
||||
self.sub_id = UUID().description
|
||||
self.profiles_id = UUID().description
|
||||
self.reposts = []
|
||||
}
|
||||
|
||||
func get_filter() -> NostrFilter {
|
||||
var filter = NostrFilter.filter_kinds([NostrKind.boost.rawValue])
|
||||
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 == NostrKind.boost.rawValue else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let reposted_event = last_etag(tags: ev.tags) else {
|
||||
return
|
||||
}
|
||||
|
||||
guard reposted_event == self.target else {
|
||||
return
|
||||
}
|
||||
|
||||
if insert_uniq_sorted_event(events: &self.reposts, 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: reposts, damus_state: state)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ enum Wallet: String, CaseIterable, Identifiable {
|
||||
appStoreLink: "https://apps.apple.com/sv/app/bitcoin-beach-wallet/id1531383905", image: "bbw")
|
||||
case .blixtwallet:
|
||||
return .init(index: 11, tag: "blixtwallet", displayName: NSLocalizedString("Blixt Wallet", comment: "Dropdown option label for Lightning wallet, Blixt Wallet"), link: "blixtwallet:lightning:",
|
||||
appStoreLink: nil, image: "blixt-wallet")
|
||||
appStoreLink: "https://testflight.apple.com/join/EXvGhRzS", image: "blixt-wallet")
|
||||
case .river:
|
||||
return .init(index: 12, tag: "river", displayName: NSLocalizedString("River", comment: "Dropdown option label for Lightning wallet, River"), link: "river://",
|
||||
appStoreLink: "https://apps.apple.com/us/app/river-buy-mine-bitcoin/id1536176542", image: "river")
|
||||
|
||||
35
damus/Modifiers/SwipeToDismiss.swift
Normal file
35
damus/Modifiers/SwipeToDismiss.swift
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// SwipeToDismiss.swift
|
||||
// damus
|
||||
//
|
||||
// Created by Joel Klabo on 1/18/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct SwipeToDismissModifier: ViewModifier {
|
||||
let minDistance: CGFloat?
|
||||
var onDismiss: () -> Void
|
||||
@State private var offset: CGSize = .zero
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
.offset(y: offset.height)
|
||||
.animation(.interactiveSpring(), value: offset)
|
||||
.simultaneousGesture(
|
||||
DragGesture(minimumDistance: minDistance ?? 10)
|
||||
.onChanged { gesture in
|
||||
if gesture.translation.width < 50 {
|
||||
offset = gesture.translation
|
||||
}
|
||||
}
|
||||
.onEnded { _ in
|
||||
if abs(offset.height) > 100 {
|
||||
onDismiss()
|
||||
} else {
|
||||
offset = .zero
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,10 @@ struct Profile: Codable {
|
||||
set(s) { value["website"] = s }
|
||||
}
|
||||
|
||||
var website_url: URL? {
|
||||
return self.website.flatMap { URL(string: $0) }
|
||||
}
|
||||
|
||||
var lud06: String? {
|
||||
get { return value["lud06"]; }
|
||||
set(s) { value["lud06"] = s }
|
||||
|
||||
@@ -789,3 +789,46 @@ func inner_event_or_self(ev: NostrEvent) -> NostrEvent {
|
||||
|
||||
return inner_ev
|
||||
}
|
||||
|
||||
func first_eref_mention(ev: NostrEvent, privkey: String?) -> Mention? {
|
||||
let blocks = ev.blocks(privkey).filter { block in
|
||||
guard case .mention(let mention) = block else {
|
||||
return false
|
||||
}
|
||||
|
||||
guard case .event = mention.type else {
|
||||
return false
|
||||
}
|
||||
|
||||
if mention.ref.key != "e" {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/// MARK: - Preview
|
||||
if let firstBlock = blocks.first, case .mention(let mention) = firstBlock, mention.ref.key == "e" {
|
||||
return mention
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
extension [ReferencedId] {
|
||||
var pRefs: [ReferencedId] {
|
||||
get {
|
||||
self.filter { ref in
|
||||
ref.key == "p"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var eRefs: [ReferencedId] {
|
||||
get {
|
||||
self.filter { ref in
|
||||
ref.key == "e"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,62 +33,41 @@ struct EventActionBar: View {
|
||||
EventActionButton(img: "bubble.left", col: nil) {
|
||||
notify(.reply, event)
|
||||
}
|
||||
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
|
||||
HStack(alignment: .bottom) {
|
||||
Spacer()
|
||||
ZStack {
|
||||
|
||||
EventActionButton(img: "arrow.2.squarepath", col: bar.boosted ? Color.green : nil) {
|
||||
if bar.boosted {
|
||||
notify(.delete, bar.our_boost)
|
||||
} else {
|
||||
} else if damus_state.is_privkey_user {
|
||||
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)
|
||||
}
|
||||
Text("\(bar.boosts > 0 ? "\(bar.boosts)" : "")")
|
||||
.offset(x: 18)
|
||||
.font(.footnote.weight(.medium))
|
||||
.foregroundColor(bar.boosted ? Color.green : Color.gray)
|
||||
}
|
||||
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
HStack(alignment: .bottom) {
|
||||
Spacer()
|
||||
ZStack {
|
||||
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)
|
||||
}
|
||||
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)
|
||||
|
||||
Spacer()
|
||||
EventActionButton(img: "square.and.arrow.up", col: Color.gray) {
|
||||
show_share_sheet = true
|
||||
}
|
||||
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
/*
|
||||
HStack(alignment: .bottom) {
|
||||
Text("\(bar.tips > 0 ? "\(bar.tips)" : "")")
|
||||
.font(.footnote)
|
||||
.foregroundColor(bar.tipped ? Color.orange : Color.gray)
|
||||
|
||||
EventActionButton(img: bar.tipped ? "bitcoinsign.circle.fill" : "bitcoinsign.circle", col: bar.tipped ? Color.orange : nil) {
|
||||
if bar.tipped {
|
||||
//notify(.delete, bar.our_tip)
|
||||
} else {
|
||||
//notify(.boost, event)
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
.sheet(isPresented: $show_share_sheet) {
|
||||
if let note_id = bech32_note_id(event.id) {
|
||||
@@ -98,7 +77,7 @@ struct EventActionBar: View {
|
||||
}
|
||||
}
|
||||
.alert(NSLocalizedString("Repost", comment: "Title of alert for confirming to repost a post."), isPresented: $confirm_boost) {
|
||||
Button("Cancel") {
|
||||
Button(NSLocalizedString("Cancel", comment: "Button to cancel out of reposting a post.")) {
|
||||
confirm_boost = false
|
||||
}
|
||||
Button(NSLocalizedString("Repost", comment: "Button to confirm reposting a post.")) {
|
||||
@@ -149,7 +128,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!)
|
||||
}
|
||||
@@ -177,8 +156,9 @@ struct EventActionBar_Previews: PreviewProvider {
|
||||
let ev = NostrEvent(content: "hi", pubkey: pk)
|
||||
|
||||
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)
|
||||
let likedbar = ActionBarModel(likes: 10, boosts: 10, tips: 0, our_like: nil, our_boost: nil, our_tip: nil)
|
||||
let likedbar_ours = ActionBarModel(likes: 100, boosts: 100, tips: 0, our_like: NostrEvent(id: "", content: "", pubkey: ""), our_boost: nil, our_tip: nil)
|
||||
let maxed_bar = ActionBarModel(likes: 999, boosts: 999, tips: 0, our_like: NostrEvent(id: "", content: "", pubkey: ""), our_boost: NostrEvent(id: "", content: "", pubkey: ""), our_tip: nil)
|
||||
|
||||
VStack(spacing: 50) {
|
||||
EventActionBar(damus_state: ds, event: ev, bar: bar)
|
||||
@@ -186,6 +166,8 @@ struct EventActionBar_Previews: PreviewProvider {
|
||||
EventActionBar(damus_state: ds, event: ev, bar: likedbar)
|
||||
|
||||
EventActionBar(damus_state: ds, event: ev, bar: likedbar_ours)
|
||||
|
||||
EventActionBar(damus_state: ds, event: ev, bar: maxed_bar)
|
||||
}
|
||||
.padding(20)
|
||||
}
|
||||
|
||||
@@ -15,27 +15,21 @@ struct EventDetailBar: View {
|
||||
var body: some View {
|
||||
HStack {
|
||||
if bar.boosts > 0 {
|
||||
Text("\(bar.boosts)")
|
||||
.font(.body.bold())
|
||||
Text("Reposts")
|
||||
.foregroundColor(.gray)
|
||||
NavigationLink(destination: RepostsView(damus_state: state, model: RepostsModel(state: state, target: target))) {
|
||||
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'.")
|
||||
}
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
}
|
||||
|
||||
if bar.likes > 0 {
|
||||
NavigationLink(destination: ReactionsView(damus_state: state, model: ReactionsModel(state: state, target: target))) {
|
||||
Text("\(bar.likes)")
|
||||
.font(.body.bold())
|
||||
Text("Reactions")
|
||||
.foregroundColor(.gray)
|
||||
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("\(bar.tips)")
|
||||
.font(.body.bold())
|
||||
Text("Tips")
|
||||
.foregroundColor(.gray)
|
||||
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'.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,29 +9,43 @@ import SwiftUI
|
||||
import Kingfisher
|
||||
|
||||
struct InnerBannerImageView: View {
|
||||
let url: URL?
|
||||
let pubkey: String
|
||||
|
||||
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 (url != nil) {
|
||||
KFAnimatedImage(url)
|
||||
if (imageModel.url != nil) {
|
||||
KFAnimatedImage(imageModel.url)
|
||||
.callbackQueue(.dispatch(.global(qos: .background)))
|
||||
.processingQueue(.dispatch(.global(qos: .background)))
|
||||
.appendProcessor(LargeImageProcessor.shared)
|
||||
.serialize(by: imageModel.serializer)
|
||||
.setProcessor(imageModel.processor)
|
||||
.configure { view in
|
||||
view.framePreloadCount = 1
|
||||
}
|
||||
.placeholder { _ in
|
||||
Image("profile-banner").resizable()
|
||||
Color(uiColor: .secondarySystemBackground)
|
||||
}
|
||||
.scaleFactor(UIScreen.main.scale)
|
||||
.loadDiskFileSynchronously()
|
||||
.fade(duration: 0.1)
|
||||
.onFailureImage(defaultImage)
|
||||
.id(imageModel.refreshID)
|
||||
} else {
|
||||
Image("profile-banner").resizable()
|
||||
Image(uiImage: defaultImage).resizable()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,7 +64,7 @@ struct BannerImageView: View {
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
InnerBannerImageView(url: get_banner_url(banner: banner, pubkey: pubkey, profiles: profiles), pubkey: pubkey)
|
||||
InnerBannerImageView(url: get_banner_url(banner: banner, pubkey: pubkey, profiles: profiles))
|
||||
.onReceive(handle_notify(.profile_updated)) { notif in
|
||||
let updated = notif.object as! ProfileUpdate
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ struct ConfigView: View {
|
||||
Section(NSLocalizedString("Secret Account Login Key", comment: "Section title for user's secret account login key.")) {
|
||||
HStack {
|
||||
if show_privkey == false {
|
||||
SecureField(NSLocalizedString("PrivateKey", comment: "Title of the secure field that holds the user's private key."), text: $privkey)
|
||||
SecureField(NSLocalizedString("Private Key", comment: "Title of the secure field that holds the user's private key."), text: $privkey)
|
||||
.disabled(true)
|
||||
} else {
|
||||
Text(sec)
|
||||
@@ -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: {
|
||||
|
||||
@@ -149,7 +149,7 @@ struct DMChatView: View {
|
||||
.opacity(((dms.events.count == 0) ? 1.0 : 0.0))
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
.navigationTitle(NSLocalizedString("DM", comment: "Navigation title for DM view, which is the English abbreviation for Direct Message."))
|
||||
.navigationTitle(NSLocalizedString("DMs", comment: "Navigation title for DMs view, where DM is the English abbreviation for Direct Message."))
|
||||
.toolbar { Header }
|
||||
}
|
||||
}
|
||||
@@ -158,7 +158,7 @@ struct DMChatView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let ev = NostrEvent(content: "hi", pubkey: "pubkey", kind: 1, tags: [])
|
||||
|
||||
let model = DirectMessageModel(events: [ev])
|
||||
let model = DirectMessageModel(events: [ev], our_pubkey: "pubkey")
|
||||
|
||||
DMChatView(damus_state: test_damus_state(), pubkey: "pubkey")
|
||||
.environmentObject(model)
|
||||
@@ -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
|
||||
|
||||
@@ -7,15 +7,26 @@
|
||||
|
||||
import SwiftUI
|
||||
|
||||
enum DMType: Hashable {
|
||||
case rando
|
||||
case friend
|
||||
}
|
||||
|
||||
struct DirectMessagesView: View {
|
||||
let damus_state: DamusState
|
||||
|
||||
@State var dm_type: DMType = .friend
|
||||
@State var open_dm: Bool = false
|
||||
@State var pubkey: String = ""
|
||||
@State var active_model: DirectMessageModel = DirectMessageModel()
|
||||
@EnvironmentObject var model: DirectMessagesModel
|
||||
@State var active_model: DirectMessageModel
|
||||
|
||||
var MainContent: some View {
|
||||
init(damus_state: DamusState) {
|
||||
self.damus_state = damus_state
|
||||
self._active_model = State(initialValue: DirectMessageModel(our_pubkey: damus_state.pubkey))
|
||||
}
|
||||
|
||||
func MainContent(requests: Bool) -> some View {
|
||||
ScrollView {
|
||||
let chat = DMChatView(damus_state: damus_state, pubkey: pubkey)
|
||||
.environmentObject(active_model)
|
||||
@@ -26,20 +37,19 @@ struct DirectMessagesView: View {
|
||||
if model.dms.isEmpty, !model.loading {
|
||||
EmptyTimelineView()
|
||||
} else {
|
||||
ForEach(model.dms, id: \.0) { tup in
|
||||
let dms = requests ? model.message_requests : model.friend_dms
|
||||
ForEach(dms, id: \.0) { tup in
|
||||
MaybeEvent(tup)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.padding(.top)
|
||||
}
|
||||
}
|
||||
|
||||
func MaybeEvent(_ tup: (String, DirectMessageModel)) -> some View {
|
||||
Group {
|
||||
if let ev = tup.1.events.last {
|
||||
EventView(damus: damus_state, event: ev, pubkey: tup.0, show_friend_icon: true)
|
||||
EventView(damus: damus_state, event: ev, pubkey: tup.0)
|
||||
.onTapGesture {
|
||||
pubkey = tup.0
|
||||
active_model = tup.1
|
||||
@@ -52,8 +62,29 @@ struct DirectMessagesView: View {
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
MainContent
|
||||
.navigationTitle(NSLocalizedString("Encrypted DMs", comment: "Navigation title for view of encrypted DMs, where DM is an English abbreviation for Direct Message."))
|
||||
VStack {
|
||||
Picker(NSLocalizedString("DM Type", comment: "DM selector for seeing either DMs or message requests, which are messages that have not been responded to yet. DM is the English abbreviation for Direct Message."), selection: $dm_type) {
|
||||
Text("DMs", comment: "Picker option for DM selector for seeing only DMs that have been responded to. DM is the English abbreviation for Direct Message.")
|
||||
.tag(DMType.friend)
|
||||
|
||||
Text("Requests", comment: "Picker option for DM selector for seeing only message requests (DMs that someone else sent the user which has not been responded to yet). DM is the English abbreviation for Direct Message.")
|
||||
.tag(DMType.rando)
|
||||
|
||||
}
|
||||
.pickerStyle(.segmented)
|
||||
|
||||
TabView(selection: $dm_type) {
|
||||
MainContent(requests: false)
|
||||
.tag(DMType.friend)
|
||||
|
||||
MainContent(requests: true)
|
||||
.tag(DMType.rando)
|
||||
}
|
||||
.tabViewStyle(.page(indexDisplayMode: .never))
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.padding(.top)
|
||||
.navigationTitle(NSLocalizedString("DMs", comment: "Navigation title for view of DMs, where DM is an English abbreviation for Direct Message."))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,8 +94,9 @@ struct DirectMessagesView_Previews: PreviewProvider {
|
||||
pubkey: "pubkey",
|
||||
kind: 4,
|
||||
tags: [])
|
||||
let model = DirectMessageModel(events: [ev])
|
||||
DirectMessagesView(damus_state: test_damus_state())
|
||||
let ds = test_damus_state()
|
||||
let model = DirectMessageModel(events: [ev], our_pubkey: ds.pubkey)
|
||||
DirectMessagesView(damus_state: ds)
|
||||
.environmentObject(model)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ struct EventDetailView: View {
|
||||
toggle_thread_view()
|
||||
}
|
||||
case .event(let ev, let highlight):
|
||||
EventView(event: ev, highlight: highlight, has_action_bar: true, damus: damus, show_friend_icon: true)
|
||||
EventView(event: ev, has_action_bar: true, damus: damus)
|
||||
.onTapGesture {
|
||||
if thread.initial_event.id == ev.id {
|
||||
toggle_thread_view()
|
||||
|
||||
@@ -8,38 +8,9 @@
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
enum Highlight {
|
||||
case none
|
||||
case main
|
||||
case reply
|
||||
case custom(Color, Float)
|
||||
|
||||
var is_main: Bool {
|
||||
if case .main = self {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var is_none: Bool {
|
||||
if case .none = self {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var is_replied_to: Bool {
|
||||
switch self {
|
||||
case .reply: return true
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum EventViewKind {
|
||||
case small
|
||||
case normal
|
||||
case big
|
||||
case selected
|
||||
}
|
||||
|
||||
@@ -49,117 +20,40 @@ func eventviewsize_to_font(_ size: EventViewKind) -> Font {
|
||||
return .body
|
||||
case .normal:
|
||||
return .body
|
||||
case .big:
|
||||
return .headline
|
||||
case .selected:
|
||||
return .custom("selected", size: 21.0)
|
||||
}
|
||||
}
|
||||
|
||||
struct BuilderEventView: View {
|
||||
let damus: DamusState
|
||||
let event_id: String
|
||||
@State var event: NostrEvent?
|
||||
@State var subscription_uuid: String = UUID().description
|
||||
|
||||
func unsubscribe() {
|
||||
damus.pool.unsubscribe(sub_id: subscription_uuid)
|
||||
}
|
||||
|
||||
func subscribe(filters: [NostrFilter]) {
|
||||
damus.pool.register_handler(sub_id: subscription_uuid, handler: handle_event)
|
||||
damus.pool.send(.subscribe(.init(filters: filters, sub_id: subscription_uuid)))
|
||||
}
|
||||
|
||||
func handle_event(relay_id: String, ev: NostrConnectionEvent) {
|
||||
guard case .nostr_event(let nostr_response) = ev else {
|
||||
return
|
||||
}
|
||||
|
||||
guard case .event(let id, let nostr_event) = nostr_response else {
|
||||
return
|
||||
}
|
||||
|
||||
// Is current event
|
||||
if id == subscription_uuid {
|
||||
if event != nil {
|
||||
return
|
||||
}
|
||||
|
||||
event = nostr_event
|
||||
|
||||
unsubscribe()
|
||||
}
|
||||
}
|
||||
|
||||
func load() {
|
||||
subscribe(filters: [
|
||||
NostrFilter(
|
||||
ids: [self.event_id],
|
||||
limit: 1
|
||||
)
|
||||
])
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
if let event = event {
|
||||
let ev = event.inner_event ?? event
|
||||
NavigationLink(destination: BuildThreadV2View(damus: damus, event_id: ev.id)) {
|
||||
EventView(damus: damus, event: event, show_friend_icon: true, size: .small)
|
||||
}.buttonStyle(.plain)
|
||||
} else {
|
||||
ProgressView().padding()
|
||||
}
|
||||
}
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
.border(Color.gray.opacity(0.2), width: 1)
|
||||
.cornerRadius(2)
|
||||
.onAppear {
|
||||
self.load()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct EventView: View {
|
||||
let event: NostrEvent
|
||||
let highlight: Highlight
|
||||
let has_action_bar: Bool
|
||||
let damus: DamusState
|
||||
let pubkey: String
|
||||
let show_friend_icon: Bool
|
||||
let size: EventViewKind
|
||||
|
||||
@EnvironmentObject var action_bar: ActionBarModel
|
||||
|
||||
init(event: NostrEvent, highlight: Highlight, has_action_bar: Bool, damus: DamusState, show_friend_icon: Bool, size: EventViewKind = .normal) {
|
||||
init(event: NostrEvent, has_action_bar: Bool, damus: DamusState) {
|
||||
self.event = event
|
||||
self.highlight = highlight
|
||||
self.has_action_bar = has_action_bar
|
||||
self.damus = damus
|
||||
self.pubkey = event.pubkey
|
||||
self.show_friend_icon = show_friend_icon
|
||||
self.size = size
|
||||
}
|
||||
|
||||
init(damus: DamusState, event: NostrEvent, show_friend_icon: Bool, size: EventViewKind = .normal) {
|
||||
init(damus: DamusState, event: NostrEvent) {
|
||||
self.event = event
|
||||
self.highlight = .none
|
||||
self.has_action_bar = false
|
||||
self.damus = damus
|
||||
self.pubkey = event.pubkey
|
||||
self.show_friend_icon = show_friend_icon
|
||||
self.size = size
|
||||
}
|
||||
|
||||
init(damus: DamusState, event: NostrEvent, pubkey: String, show_friend_icon: Bool, size: EventViewKind = .normal, embedded: Bool = false) {
|
||||
init(damus: DamusState, event: NostrEvent, pubkey: String) {
|
||||
self.event = event
|
||||
self.highlight = .none
|
||||
self.has_action_bar = false
|
||||
self.damus = damus
|
||||
self.pubkey = pubkey
|
||||
self.show_friend_icon = show_friend_icon
|
||||
self.size = size
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
@@ -175,7 +69,7 @@ struct EventView: View {
|
||||
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 {
|
||||
@@ -185,80 +79,42 @@ struct EventView: View {
|
||||
}
|
||||
}
|
||||
|
||||
func TextEvent(_ event: NostrEvent, pubkey: String) -> some View {
|
||||
let content = event.get_content(damus.keypair.privkey)
|
||||
|
||||
func TextEvent(_ event: NostrEvent, pubkey: String, booster_pubkey: String? = nil) -> some View {
|
||||
return HStack(alignment: .top) {
|
||||
let profile = damus.profiles.lookup(id: pubkey)
|
||||
|
||||
if size != .selected {
|
||||
VStack {
|
||||
let pmodel = ProfileModel(pubkey: pubkey, damus: damus)
|
||||
let pv = ProfileView(damus_state: damus, profile: pmodel, followers: FollowersModel(damus_state: damus, target: pubkey))
|
||||
|
||||
NavigationLink(destination: pv) {
|
||||
ProfilePicView(pubkey: pubkey, size: PFP_SIZE, highlight: highlight, profiles: damus.profiles)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
VStack {
|
||||
let pmodel = ProfileModel(pubkey: pubkey, damus: damus)
|
||||
let pv = ProfileView(damus_state: damus, profile: pmodel, followers: FollowersModel(damus_state: damus, target: pubkey))
|
||||
|
||||
NavigationLink(destination: pv) {
|
||||
ProfilePicView(pubkey: pubkey, size: PFP_SIZE, highlight: .none, profiles: damus.profiles)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
HStack(alignment: .center) {
|
||||
if size == .selected {
|
||||
VStack {
|
||||
let pmodel = ProfileModel(pubkey: pubkey, damus: damus)
|
||||
let pv = ProfileView(damus_state: damus, profile: pmodel, followers: FollowersModel(damus_state: damus, target: pubkey))
|
||||
|
||||
NavigationLink(destination: pv) {
|
||||
ProfilePicView(pubkey: pubkey, size: PFP_SIZE, highlight: highlight, profiles: damus.profiles)
|
||||
}
|
||||
}
|
||||
}
|
||||
EventProfileName(pubkey: pubkey, profile: profile, damus: damus, show_friend_confirmed: true, size: .normal)
|
||||
|
||||
EventProfileName(pubkey: pubkey, profile: profile, damus: damus, show_friend_confirmed: show_friend_icon, size: size)
|
||||
if size != .selected {
|
||||
Text("\(format_relative_time(event.created_at))")
|
||||
.font(eventviewsize_to_font(size))
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
}
|
||||
|
||||
if event.is_reply(damus.keypair.privkey) {
|
||||
Text("\(reply_desc(profiles: damus.profiles, event: event))")
|
||||
.font(.footnote)
|
||||
Text("\(format_relative_time(event.created_at))")
|
||||
.foregroundColor(.gray)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
|
||||
let should_show_img = should_show_images(contacts: damus.contacts, ev: event, our_pubkey: damus.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)
|
||||
EventBody(damus_state: damus, event: event, size: .normal)
|
||||
|
||||
if let mention = first_eref_mention(ev: event, privkey: damus.keypair.privkey) {
|
||||
BuilderEventView(damus: damus, event_id: mention.ref.id)
|
||||
}
|
||||
|
||||
if has_action_bar {
|
||||
if size == .selected {
|
||||
Text("\(format_date(event.created_at))")
|
||||
.padding(.top, 10)
|
||||
.font(.footnote)
|
||||
.foregroundColor(.gray)
|
||||
|
||||
Divider()
|
||||
.padding([.bottom], 4)
|
||||
} else {
|
||||
Rectangle().frame(height: 2).opacity(0)
|
||||
}
|
||||
Rectangle().frame(height: 2).opacity(0)
|
||||
|
||||
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)
|
||||
.padding([.top], 4)
|
||||
}
|
||||
|
||||
Divider()
|
||||
@@ -276,13 +132,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
|
||||
}
|
||||
|
||||
@@ -321,19 +180,19 @@ extension View {
|
||||
Button {
|
||||
UIPasteboard.general.string = bech32_pubkey(pubkey) ?? pubkey
|
||||
} label: {
|
||||
Label(NSLocalizedString("Copy User ID", comment: "Context menu option for copying the ID of the user who created the note."), systemImage: "tag")
|
||||
Label(NSLocalizedString("Copy User ID", comment: "Context menu option for copying the ID of the user who created the note."), systemImage: "person")
|
||||
}
|
||||
|
||||
Button {
|
||||
UIPasteboard.general.string = bech32_note_id(event.id) ?? event.id
|
||||
} label: {
|
||||
Label(NSLocalizedString("Copy Note ID", comment: "Context menu option for copying the ID of the note."), systemImage: "tag")
|
||||
Label(NSLocalizedString("Copy Note ID", comment: "Context menu option for copying the ID of the note."), systemImage: "note.text")
|
||||
}
|
||||
|
||||
Button {
|
||||
UIPasteboard.general.string = event_to_json(ev: event)
|
||||
} label: {
|
||||
Label(NSLocalizedString("Copy Note JSON", comment: "Context menu option for copying the JSON text from the note."), systemImage: "note")
|
||||
Label(NSLocalizedString("Copy Note JSON", comment: "Context menu option for copying the JSON text from the note."), systemImage: "j.square.on.square")
|
||||
}
|
||||
|
||||
Button {
|
||||
@@ -360,33 +219,6 @@ func format_date(_ created_at: Int64) -> String {
|
||||
}
|
||||
|
||||
|
||||
func reply_desc(profiles: Profiles, event: NostrEvent) -> String {
|
||||
let desc = make_reply_description(event.tags)
|
||||
let pubkeys = desc.pubkeys
|
||||
let n = desc.others
|
||||
|
||||
if desc.pubkeys.count == 0 {
|
||||
return NSLocalizedString("Reply to self", comment: "Label to indicate that the user is replying to themself.")
|
||||
}
|
||||
|
||||
let names: [String] = pubkeys.map {
|
||||
let prof = profiles.lookup(id: $0)
|
||||
return Profile.displayName(profile: prof, pubkey: $0)
|
||||
}
|
||||
|
||||
if names.count == 2 {
|
||||
if n > 2 {
|
||||
let othersCount = n - pubkeys.count
|
||||
return String(format: NSLocalizedString("replying_to_two_and_others", comment: "Label to indicate that the user is replying to 2 users and others."), names[0], names[1], othersCount)
|
||||
}
|
||||
return String(format: NSLocalizedString("Replying to %@ & %@", comment: "Label to indicate that the user is replying to 2 users."), names[0], names[1])
|
||||
}
|
||||
|
||||
let othersCount = n - pubkeys.count
|
||||
return String(format: NSLocalizedString("replying_to_one_and_others", comment: "Label to indicate that the user is replying to 1 user and others."), names[0], othersCount)
|
||||
}
|
||||
|
||||
|
||||
|
||||
func make_actionbar_model(ev: NostrEvent, damus: DamusState) -> ActionBarModel {
|
||||
let likes = damus.likes.counts[ev.id]
|
||||
@@ -409,22 +241,25 @@ func make_actionbar_model(ev: NostrEvent, damus: DamusState) -> ActionBarModel {
|
||||
struct EventView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
VStack {
|
||||
/*
|
||||
EventView(damus: test_damus_state(), event: NostrEvent(content: "hello there https://jb55.com/s/Oct12-150217.png https://jb55.com/red-me.jb55 cool", pubkey: "pk"), show_friend_icon: true, size: .small)
|
||||
EventView(damus: test_damus_state(), event: NostrEvent(content: "hello there https://jb55.com/s/Oct12-150217.png https://jb55.com/red-me.jb55 cool", pubkey: "pk"), show_friend_icon: true, size: .normal)
|
||||
EventView(damus: test_damus_state(), event: NostrEvent(content: "hello there https://jb55.com/s/Oct12-150217.png https://jb55.com/red-me.jb55 cool", pubkey: "pk"), show_friend_icon: true, size: .big)
|
||||
|
||||
*/
|
||||
EventView(
|
||||
event: NostrEvent(
|
||||
content: "hello there https://jb55.com/s/Oct12-150217.png https://jb55.com/red-me.jb55 cool",
|
||||
pubkey: "pk",
|
||||
createdAt: Int64(Date().timeIntervalSince1970 - 100)
|
||||
),
|
||||
highlight: .none,
|
||||
event: test_event,
|
||||
has_action_bar: true,
|
||||
damus: test_damus_state(),
|
||||
show_friend_icon: true,
|
||||
size: .selected
|
||||
damus: test_damus_state()
|
||||
)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
let test_event =
|
||||
NostrEvent(
|
||||
content: "hello there https://jb55.com/s/Oct12-150217.png https://jb55.com/red-me.jpg cool",
|
||||
pubkey: "pk",
|
||||
createdAt: Int64(Date().timeIntervalSince1970 - 100)
|
||||
)
|
||||
|
||||
81
damus/Views/Events/BuilderEventView.swift
Normal file
81
damus/Views/Events/BuilderEventView.swift
Normal file
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// BuilderEventView.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-01-23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct BuilderEventView: View {
|
||||
let damus: DamusState
|
||||
let event_id: String
|
||||
@State var event: NostrEvent?
|
||||
@State var subscription_uuid: String = UUID().description
|
||||
|
||||
func unsubscribe() {
|
||||
damus.pool.unsubscribe(sub_id: subscription_uuid)
|
||||
}
|
||||
|
||||
func subscribe(filters: [NostrFilter]) {
|
||||
damus.pool.register_handler(sub_id: subscription_uuid, handler: handle_event)
|
||||
damus.pool.send(.subscribe(.init(filters: filters, sub_id: subscription_uuid)))
|
||||
}
|
||||
|
||||
func handle_event(relay_id: String, ev: NostrConnectionEvent) {
|
||||
guard case .nostr_event(let nostr_response) = ev else {
|
||||
return
|
||||
}
|
||||
|
||||
guard case .event(let id, let nostr_event) = nostr_response else {
|
||||
return
|
||||
}
|
||||
|
||||
// Is current event
|
||||
if id == subscription_uuid {
|
||||
if event != nil {
|
||||
return
|
||||
}
|
||||
|
||||
event = nostr_event
|
||||
|
||||
unsubscribe()
|
||||
}
|
||||
}
|
||||
|
||||
func load() {
|
||||
subscribe(filters: [
|
||||
NostrFilter(
|
||||
ids: [self.event_id],
|
||||
limit: 1
|
||||
)
|
||||
])
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
if let event = event {
|
||||
let ev = event.inner_event ?? event
|
||||
NavigationLink(destination: BuildThreadV2View(damus: damus, event_id: ev.id)) {
|
||||
EmbeddedEventView(damus_state: damus, event: event)
|
||||
.padding(8)
|
||||
}.buttonStyle(.plain)
|
||||
} else {
|
||||
ProgressView().padding()
|
||||
}
|
||||
}
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
.cornerRadius(8)
|
||||
.border(Color.gray.opacity(0.2), width: 1)
|
||||
.onAppear {
|
||||
self.load()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct BuilderEventView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
BuilderEventView(damus: test_damus_state(), event_id: "536bee9e83c818e3b82c101935128ae27a0d4290039aaf253efe5f09232c1962")
|
||||
}
|
||||
}
|
||||
|
||||
34
damus/Views/Events/EmbeddedEventView.swift
Normal file
34
damus/Views/Events/EmbeddedEventView.swift
Normal file
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// EmbeddedEventView.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-01-23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct EmbeddedEventView: View {
|
||||
let damus_state: DamusState
|
||||
let event: NostrEvent
|
||||
|
||||
var pubkey: String {
|
||||
event.pubkey
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
let profile = damus_state.profiles.lookup(id: pubkey)
|
||||
|
||||
EventProfile(damus_state: damus_state, pubkey: pubkey, profile: profile, size: .small)
|
||||
|
||||
EventBody(damus_state: damus_state, event: event, size: .small)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct EmbeddedEventView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
EmbeddedEventView(damus_state: test_damus_state(), event: test_event)
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
35
damus/Views/Events/EventBody.swift
Normal file
35
damus/Views/Events/EventBody.swift
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// EventBody.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-01-23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct EventBody: View {
|
||||
let damus_state: DamusState
|
||||
let event: NostrEvent
|
||||
let size: EventViewKind
|
||||
|
||||
var content: String {
|
||||
event.get_content(damus_state.keypair.privkey)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
if event_is_reply(event, privkey: damus_state.keypair.privkey) {
|
||||
ReplyDescription(event: event, profiles: damus_state.profiles)
|
||||
}
|
||||
|
||||
let should_show_img = should_show_images(contacts: damus_state.contacts, ev: event, our_pubkey: damus_state.pubkey, booster_pubkey: nil)
|
||||
|
||||
NoteContentView(privkey: damus_state.keypair.privkey, event: event, profiles: damus_state.profiles, previews: damus_state.previews, show_images: should_show_img, artifacts: .just_content(content), size: size)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
}
|
||||
|
||||
struct EventBody_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
EventBody(damus_state: test_damus_state(), event: test_event, size: .normal)
|
||||
}
|
||||
}
|
||||
51
damus/Views/Events/EventProfile.swift
Normal file
51
damus/Views/Events/EventProfile.swift
Normal file
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// EventProfile.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-01-23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
func eventview_pfp_size(_ size: EventViewKind) -> CGFloat {
|
||||
switch size {
|
||||
case .small:
|
||||
return PFP_SIZE * 0.5
|
||||
case .normal:
|
||||
return PFP_SIZE
|
||||
case .selected:
|
||||
return PFP_SIZE
|
||||
}
|
||||
}
|
||||
|
||||
struct EventProfile: View {
|
||||
let damus_state: DamusState
|
||||
let pubkey: String
|
||||
let profile: Profile?
|
||||
let size: EventViewKind
|
||||
|
||||
var pfp_size: CGFloat {
|
||||
eventview_pfp_size(size)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .center) {
|
||||
VStack {
|
||||
let pmodel = ProfileModel(pubkey: pubkey, damus: damus_state)
|
||||
let pv = ProfileView(damus_state: damus_state, profile: pmodel, followers: FollowersModel(damus_state: damus_state, target: pubkey))
|
||||
|
||||
NavigationLink(destination: pv) {
|
||||
ProfilePicView(pubkey: pubkey, size: pfp_size, highlight: .none, profiles: damus_state.profiles)
|
||||
}
|
||||
}
|
||||
|
||||
EventProfileName(pubkey: pubkey, profile: profile, damus: damus_state, show_friend_confirmed: true, size: size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct EventProfile_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
EventProfile(damus_state: test_damus_state(), pubkey: "pk", profile: nil, size: .normal)
|
||||
}
|
||||
}
|
||||
55
damus/Views/Events/ReplyDescription.swift
Normal file
55
damus/Views/Events/ReplyDescription.swift
Normal file
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// ReplyDescription.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-01-23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
// jb55 - TODO: this could be a lot better
|
||||
struct ReplyDescription: View {
|
||||
let event: NostrEvent
|
||||
let profiles: Profiles
|
||||
|
||||
var body: some View {
|
||||
Text("\(reply_desc(profiles: profiles, event: event))")
|
||||
.font(.footnote)
|
||||
.foregroundColor(.gray)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
}
|
||||
|
||||
struct ReplyDescription_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ReplyDescription(event: test_event, profiles: test_damus_state().profiles)
|
||||
}
|
||||
}
|
||||
|
||||
func reply_desc(profiles: Profiles, event: NostrEvent) -> String {
|
||||
let desc = make_reply_description(event.tags)
|
||||
let pubkeys = desc.pubkeys
|
||||
let n = desc.others
|
||||
|
||||
if desc.pubkeys.count == 0 {
|
||||
return NSLocalizedString("Reply to self", comment: "Label to indicate that the user is replying to themself.")
|
||||
}
|
||||
|
||||
let names: [String] = pubkeys.map {
|
||||
let prof = profiles.lookup(id: $0)
|
||||
return Profile.displayName(profile: prof, pubkey: $0)
|
||||
}
|
||||
|
||||
if names.count == 2 {
|
||||
if n > 2 {
|
||||
let othersCount = n - pubkeys.count
|
||||
return String(format: NSLocalizedString("replying_to_two_and_others", comment: "Label to indicate that the user is replying to 2 users and others."), names[0], names[1], othersCount)
|
||||
}
|
||||
return String(format: NSLocalizedString("Replying to %@ & %@", comment: "Label to indicate that the user is replying to 2 users."), names[0], names[1])
|
||||
}
|
||||
|
||||
let othersCount = n - pubkeys.count
|
||||
return String(format: NSLocalizedString("replying_to_one_and_others", comment: "Label to indicate that the user is replying to 1 user and others."), names[0], othersCount)
|
||||
}
|
||||
|
||||
|
||||
61
damus/Views/Events/SelectedEventView.swift
Normal file
61
damus/Views/Events/SelectedEventView.swift
Normal file
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// SelectedEventView.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-01-23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct SelectedEventView: View {
|
||||
let damus: DamusState
|
||||
let event: NostrEvent
|
||||
|
||||
var pubkey: String {
|
||||
event.pubkey
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .top) {
|
||||
let profile = damus.profiles.lookup(id: pubkey)
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
EventProfile(damus_state: damus, pubkey: pubkey, profile: profile, size: .normal)
|
||||
EventBody(damus_state: damus, event: event, size: .selected)
|
||||
|
||||
if let mention = first_eref_mention(ev: event, privkey: damus.keypair.privkey) {
|
||||
BuilderEventView(damus: damus, event_id: mention.ref.id)
|
||||
}
|
||||
|
||||
Text("\(format_date(event.created_at))")
|
||||
.padding(.top, 10)
|
||||
.font(.footnote)
|
||||
.foregroundColor(.gray)
|
||||
|
||||
Divider()
|
||||
.padding([.bottom], 4)
|
||||
|
||||
let bar = make_actionbar_model(ev: event, damus: damus)
|
||||
|
||||
if !bar.is_empty {
|
||||
EventDetailBar(state: damus, target: event.id, bar: bar)
|
||||
Divider()
|
||||
}
|
||||
|
||||
EventActionBar(damus_state: damus, event: event, bar: bar)
|
||||
.padding([.top], 4)
|
||||
|
||||
Divider()
|
||||
.padding([.top], 4)
|
||||
}
|
||||
.padding([.leading], 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SelectedEventView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
SelectedEventView(damus: test_damus_state(), event: test_event)
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,7 @@ struct FollowButtonView: View {
|
||||
follow_state = perform_follow_btn_action(follow_state, target: target)
|
||||
} label: {
|
||||
Text(follow_btn_txt(follow_state))
|
||||
.frame(height: 30)
|
||||
.padding(.horizontal, 25)
|
||||
.frame(width: 105, height: 30)
|
||||
//.padding(.vertical, 10)
|
||||
.font(.caption.weight(.bold))
|
||||
.foregroundColor(follow_state == .unfollows ? filledTextColor() : borderColor())
|
||||
|
||||
20
damus/Views/ImageView.swift
Normal file
20
damus/Views/ImageView.swift
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// ImageView.swift
|
||||
// damus
|
||||
//
|
||||
// Created by user232838 on 1/5/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ImageView: View {
|
||||
var body: some View {
|
||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
||||
}
|
||||
}
|
||||
|
||||
struct ImageView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ImageView()
|
||||
}
|
||||
}
|
||||
33
damus/Views/MagnificationGestureView.swift
Normal file
33
damus/Views/MagnificationGestureView.swift
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// MagnificationGestureView.swift
|
||||
// damus
|
||||
//
|
||||
// Created by user232838 on 1/5/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct MagnificationGestureView: View {
|
||||
|
||||
@GestureState var magnifyBy = 1.0
|
||||
|
||||
var magnification: some Gesture {
|
||||
MagnificationGesture()
|
||||
.updating($magnifyBy) { currentState, gestureState, transaction in
|
||||
gestureState = currentState
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Circle()
|
||||
.frame(width: 100, height: 100)
|
||||
.scaleEffect(magnifyBy)
|
||||
.gesture(magnification)
|
||||
}
|
||||
}
|
||||
|
||||
struct MagnificationGestureView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
MagnificationGestureView()
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ func render_note_content(ev: NostrEvent, profiles: Profiles, privkey: String?) -
|
||||
}
|
||||
|
||||
func is_image_url(_ url: URL) -> Bool {
|
||||
let str = url.lastPathComponent
|
||||
let str = url.lastPathComponent.lowercased()
|
||||
return str.hasSuffix("png") || str.hasSuffix("jpg") || str.hasSuffix("jpeg") || str.hasSuffix("gif")
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
79
damus/Views/ParicipantsView.swift
Normal file
79
damus/Views/ParicipantsView.swift
Normal file
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// ParicipantsView.swift
|
||||
// damus
|
||||
//
|
||||
// Created by Joel Klabo on 1/18/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ParticipantsView: View {
|
||||
|
||||
let damus_state: DamusState
|
||||
|
||||
@Binding var references: [ReferencedId]
|
||||
@Binding var originalReferences: [ReferencedId]
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Text("Edit participants", comment: "Text indicating that the view is used for editing which participants are replied to in a note.")
|
||||
HStack {
|
||||
Spacer()
|
||||
Button {
|
||||
// Remove all "p" refs, keep "e" refs
|
||||
references = originalReferences.eRefs
|
||||
} label: {
|
||||
Text("Remove all", comment: "Button label to remove all participants from a note reply.")
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
Spacer()
|
||||
Button {
|
||||
references = originalReferences
|
||||
} label: {
|
||||
Text("Add all", comment: "Button label to re-add all original participants as profiles to reply to in a note")
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
Spacer()
|
||||
}
|
||||
VStack {
|
||||
ForEach(originalReferences.pRefs) { participant in
|
||||
let pubkey = participant.id
|
||||
HStack {
|
||||
ProfilePicView(pubkey: pubkey, size: PFP_SIZE, highlight: .none, profiles: damus_state.profiles)
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
let profile = damus_state.profiles.lookup(id: pubkey)
|
||||
ProfileName(pubkey: pubkey, profile: profile, damus: damus_state, show_friend_confirmed: false, show_nip5_domain: false)
|
||||
if let about = profile?.about {
|
||||
Text(FollowUserView.markdown.process(about))
|
||||
.lineLimit(3)
|
||||
.font(.footnote)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
.font(.system(size: 30))
|
||||
.foregroundColor(references.contains(participant) ? .purple : .gray)
|
||||
}
|
||||
.onTapGesture {
|
||||
if references.contains(participant) {
|
||||
references = references.filter {
|
||||
$0 != participant
|
||||
}
|
||||
} else {
|
||||
if references.contains(participant) {
|
||||
// Don't add it twice
|
||||
} else {
|
||||
references.append(participant)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -118,7 +118,8 @@ struct ProfileView: View {
|
||||
|
||||
@Environment(\.dismiss) var dismiss
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
|
||||
@Environment(\.openURL) var openURL
|
||||
|
||||
// We just want to have a white "< Home" text here, however,
|
||||
// setting the initialiser is causing issues, and it's late.
|
||||
// Ref: https://blog.techchee.com/navigation-bar-title-style-color-and-custom-back-button-in-swiftui/
|
||||
@@ -190,19 +191,48 @@ struct ProfileView: View {
|
||||
.foregroundStyle(colorScheme == .dark ? .white : .black, colorScheme == .dark ? .white : .black)
|
||||
}
|
||||
}
|
||||
|
||||
private func getScrollOffset(_ geometry: GeometryProxy) -> CGFloat {
|
||||
geometry.frame(in: .global).minY
|
||||
}
|
||||
|
||||
private func getHeightForHeaderImage(_ geometry: GeometryProxy) -> CGFloat {
|
||||
let offset = getScrollOffset(geometry)
|
||||
let imageHeight = 150.0
|
||||
|
||||
if offset > 0 {
|
||||
return imageHeight + offset
|
||||
}
|
||||
|
||||
return imageHeight
|
||||
}
|
||||
|
||||
private func getOffsetForHeaderImage(_ geometry: GeometryProxy) -> CGFloat {
|
||||
let offset = getScrollOffset(geometry)
|
||||
|
||||
// Image was pulled down
|
||||
if offset > 0 {
|
||||
return -offset
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
var TopSection: some View {
|
||||
ZStack(alignment: .top) {
|
||||
GeometryReader { geo in
|
||||
GeometryReader { geometry in
|
||||
BannerImageView(pubkey: profile.pubkey, profiles: damus_state.profiles)
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: geo.size.width, height: BANNER_HEIGHT)
|
||||
.frame(width: geometry.size.width, height: self.getHeightForHeaderImage(geometry))
|
||||
.clipped()
|
||||
.offset(x: 0, y: self.getOffsetForHeaderImage(geometry))
|
||||
|
||||
ShareButton
|
||||
.offset(x: geo.size.width - 80.0, y: 50.0 )
|
||||
.offset(x: geometry.size.width - 80.0, y: 50.0 )
|
||||
|
||||
}.frame(height: BANNER_HEIGHT)
|
||||
VStack(alignment: .leading) {
|
||||
|
||||
VStack(alignment: .leading, spacing: 8.0) {
|
||||
let data = damus_state.profiles.lookup(id: profile.pubkey)
|
||||
let pfp_size: CGFloat = 90.0
|
||||
|
||||
@@ -211,9 +241,8 @@ struct ProfileView: View {
|
||||
.onTapGesture {
|
||||
is_zoomed.toggle()
|
||||
}
|
||||
.sheet(isPresented: $is_zoomed) {
|
||||
ProfilePicView(pubkey: profile.pubkey, size: zoom_size, highlight: .none, profiles: damus_state.profiles)
|
||||
}
|
||||
.fullScreenCover(isPresented: $is_zoomed) {
|
||||
ProfileZoomView(pubkey: profile.pubkey, profiles: damus_state.profiles) }
|
||||
.offset(y: -(pfp_size/2.0)) // Increase if set a frame
|
||||
|
||||
Spacer()
|
||||
@@ -251,6 +280,10 @@ struct ProfileView: View {
|
||||
Text(ProfileView.markdown.process(data?.about ?? ""))
|
||||
.font(.subheadline)
|
||||
|
||||
if let url = data?.website_url {
|
||||
WebsiteLink(url: url)
|
||||
}
|
||||
|
||||
Divider()
|
||||
|
||||
HStack {
|
||||
@@ -282,7 +315,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())
|
||||
}
|
||||
@@ -296,13 +329,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'.")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -355,7 +389,7 @@ struct ProfileView_Previews: PreviewProvider {
|
||||
|
||||
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 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(our_pubkey: pubkey), previews: PreviewCache())
|
||||
|
||||
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)
|
||||
|
||||
97
damus/Views/ProfileZoomView.swift
Normal file
97
damus/Views/ProfileZoomView.swift
Normal file
@@ -0,0 +1,97 @@
|
||||
//
|
||||
// ProfileZoomView.swift
|
||||
// damus
|
||||
//
|
||||
// Created by scoder1747 on 12/27/22.
|
||||
//
|
||||
import SwiftUI
|
||||
|
||||
struct ProfileZoomView: View {
|
||||
|
||||
@Environment(\.presentationMode) var presentationMode
|
||||
let pubkey: String
|
||||
let profiles: Profiles
|
||||
|
||||
@GestureState private var scaleState: CGFloat = 1
|
||||
@GestureState private var offsetState = CGSize.zero
|
||||
|
||||
@State private var offset = CGSize.zero
|
||||
@State private var scale: CGFloat = 1
|
||||
|
||||
func resetStatus(){
|
||||
self.offset = CGSize.zero
|
||||
self.scale = 1
|
||||
}
|
||||
|
||||
var zoomGesture: some Gesture {
|
||||
MagnificationGesture()
|
||||
.updating($scaleState) { currentState, gestureState, _ in
|
||||
gestureState = currentState
|
||||
}
|
||||
.onEnded { value in
|
||||
scale *= value
|
||||
}
|
||||
}
|
||||
|
||||
var dragGesture: some Gesture {
|
||||
DragGesture()
|
||||
.updating($offsetState) { currentState, gestureState, _ in
|
||||
gestureState = currentState.translation
|
||||
}.onEnded { value in
|
||||
offset.height += value.translation.height
|
||||
offset.width += value.translation.width
|
||||
}
|
||||
}
|
||||
|
||||
var doubleTapGesture : some Gesture {
|
||||
TapGesture(count: 2).onEnded { value in
|
||||
resetStatus()
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack(alignment: .topLeading) {
|
||||
Color("DamusDarkGrey") // Or Color("DamusBlack")
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
|
||||
Button {
|
||||
presentationMode.wrappedValue.dismiss()
|
||||
} label: {
|
||||
Image(systemName: "xmark")
|
||||
.foregroundColor(.white)
|
||||
.font(.subheadline)
|
||||
.padding(.leading, 20)
|
||||
}
|
||||
.zIndex(1)
|
||||
|
||||
VStack(alignment: .center) {
|
||||
|
||||
Spacer()
|
||||
|
||||
ProfilePicView(pubkey: pubkey, size: 200.0, highlight: .none, profiles: profiles)
|
||||
.padding(100)
|
||||
.scaledToFit()
|
||||
.scaleEffect(self.scale * scaleState)
|
||||
.offset(x: offset.width + offsetState.width, y: offset.height + offsetState.height)
|
||||
.gesture(SimultaneousGesture(zoomGesture, dragGesture))
|
||||
.gesture(doubleTapGesture)
|
||||
.modifier(SwipeToDismissModifier(minDistance: nil, onDismiss: {
|
||||
presentationMode.wrappedValue.dismiss()
|
||||
}))
|
||||
|
||||
Spacer()
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ProfileZoomView_Previews: PreviewProvider {
|
||||
static let pubkey = "ca48854ac6555fed8e439ebb4fa2d928410e0eef13fa41164ec45aaaa132d846"
|
||||
|
||||
static var previews: some View {
|
||||
ProfileZoomView(
|
||||
pubkey: pubkey,
|
||||
profiles: make_preview_profiles(pubkey))
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ struct ReactionsView: View {
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.navigationBarTitle("Reactions")
|
||||
.navigationBarTitle(NSLocalizedString("Reactions", comment: "Navigation bar title for Reactions view."))
|
||||
.onAppear {
|
||||
model.subscribe()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -18,11 +18,16 @@ struct ReplyView: View {
|
||||
let replying_to: NostrEvent
|
||||
let damus: DamusState
|
||||
|
||||
@State var originalReferences: [ReferencedId] = []
|
||||
@State var references: [ReferencedId] = []
|
||||
|
||||
@State var participantsShown: Bool = false
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Text("Replying to:", comment: "Indicating that the user is replying to the following listed people.")
|
||||
HStack(alignment: .top) {
|
||||
let names = all_referenced_pubkeys(replying_to)
|
||||
let names = references.pRefs
|
||||
.map { pubkey in
|
||||
let pk = pubkey.ref_id
|
||||
let prof = damus.profiles.lookup(id: pk)
|
||||
@@ -33,13 +38,22 @@ struct ReplyView: View {
|
||||
.foregroundColor(.gray)
|
||||
.font(.footnote)
|
||||
}
|
||||
ScrollView {
|
||||
EventView(event: replying_to, highlight: .none, has_action_bar: false, damus: damus, show_friend_icon: true)
|
||||
.onTapGesture {
|
||||
participantsShown.toggle()
|
||||
}
|
||||
PostView(replying_to: replying_to, references: gather_reply_ids(our_pubkey: damus.pubkey, from: replying_to))
|
||||
.sheet(isPresented: $participantsShown) {
|
||||
ParticipantsView(damus_state: damus, references: $references, originalReferences: $originalReferences)
|
||||
}
|
||||
ScrollView {
|
||||
EventView(event: replying_to, has_action_bar: false, damus: damus)
|
||||
}
|
||||
PostView(replying_to: replying_to, references: references)
|
||||
}
|
||||
.onAppear {
|
||||
references = gather_reply_ids(our_pubkey: damus.pubkey, from: replying_to)
|
||||
originalReferences = references
|
||||
}
|
||||
.padding()
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +61,6 @@ struct ReplyView: View {
|
||||
|
||||
struct ReplyView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ReplyView(replying_to: NostrEvent(content: "hi", pubkey: "pubkey"), damus: test_damus_state())
|
||||
ReplyView(replying_to: NostrEvent(content: "hi", pubkey: "pubkey"), damus: test_damus_state(), references: [])
|
||||
}
|
||||
}
|
||||
|
||||
24
damus/Views/Reposts/RepostView.swift
Normal file
24
damus/Views/Reposts/RepostView.swift
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// RepostView.swift
|
||||
// damus
|
||||
//
|
||||
// Created by Terry Yiu on 1/22/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct RepostView: View {
|
||||
let damus_state: DamusState
|
||||
let repost: NostrEvent
|
||||
|
||||
var body: some View {
|
||||
FollowUserView(target: .pubkey(repost.pubkey), damus_state: damus_state)
|
||||
}
|
||||
}
|
||||
|
||||
struct RepostView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
RepostView(damus_state: test_damus_state(), repost: NostrEvent(id: "", content: "", pubkey: ""))
|
||||
}
|
||||
}
|
||||
|
||||
38
damus/Views/RepostsView.swift
Normal file
38
damus/Views/RepostsView.swift
Normal file
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// RepostsView.swift
|
||||
// damus
|
||||
//
|
||||
// Created by Terry Yiu on 1/22/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct RepostsView: View {
|
||||
let damus_state: DamusState
|
||||
@StateObject var model: RepostsModel
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
LazyVStack {
|
||||
ForEach(model.reposts, id: \.id) { ev in
|
||||
RepostView(damus_state: damus_state, repost: ev)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.navigationBarTitle(NSLocalizedString("Reposts", comment: "Navigation bar title for Reposts view."))
|
||||
.onAppear {
|
||||
model.subscribe()
|
||||
}
|
||||
.onDisappear {
|
||||
model.unsubscribe()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct RepostsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let state = test_damus_state()
|
||||
RepostsView(damus_state: state, model: RepostsModel(state: state, target: "pubkey"))
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -16,7 +16,7 @@ struct SideMenuView: View {
|
||||
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
|
||||
var sideBarWidth = UIScreen.main.bounds.size.width * 0.65
|
||||
var sideBarWidth = min(UIScreen.main.bounds.size.width * 0.65, 400.0)
|
||||
|
||||
func fillColor() -> Color {
|
||||
colorScheme == .light ? Color("DamusWhite") : Color("DamusBlack")
|
||||
@@ -50,22 +50,26 @@ 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)
|
||||
} else {
|
||||
Image(systemName: "person.fill")
|
||||
}
|
||||
VStack(alignment: .leading) {
|
||||
if let display_name = profile?.display_name {
|
||||
Text(display_name)
|
||||
.foregroundColor(textColor())
|
||||
.font(.title)
|
||||
NavigationLink(destination: ProfileView(damus_state: damus_state, profile: profile_model, followers: followers)) {
|
||||
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)
|
||||
} else {
|
||||
Image(systemName: "person.fill")
|
||||
}
|
||||
if let name = profile?.name {
|
||||
Text("@" + name)
|
||||
.foregroundColor(Color("DamusMediumGrey"))
|
||||
.font(.body)
|
||||
VStack(alignment: .leading) {
|
||||
if let display_name = profile?.display_name {
|
||||
Text(display_name)
|
||||
.foregroundColor(textColor())
|
||||
.font(.title)
|
||||
}
|
||||
if let name = profile?.name {
|
||||
Text("@" + name)
|
||||
.foregroundColor(Color("DamusMediumGrey"))
|
||||
.font(.body)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -255,14 +255,7 @@ struct ThreadV2View: View {
|
||||
// MARK: - Parents events view
|
||||
VStack {
|
||||
ForEach(thread.parentEvents, id: \.id) { event in
|
||||
EventView(
|
||||
event: event,
|
||||
highlight: .none,
|
||||
has_action_bar: true,
|
||||
damus: damus,
|
||||
show_friend_icon: true, // TODO: change it
|
||||
size: .small
|
||||
)
|
||||
EventView(event: event, has_action_bar: true, damus: damus)
|
||||
.onTapGesture {
|
||||
nav_target = event.id
|
||||
navigating = true
|
||||
@@ -285,24 +278,17 @@ struct ThreadV2View: View {
|
||||
})
|
||||
|
||||
// MARK: - Actual event view
|
||||
EventView(
|
||||
event: thread.current,
|
||||
highlight: .none,
|
||||
has_action_bar: true,
|
||||
SelectedEventView(
|
||||
damus: damus,
|
||||
show_friend_icon: true, // TODO: change it
|
||||
size: .selected
|
||||
event: thread.current
|
||||
).id("main")
|
||||
|
||||
// MARK: - Responses of the actual event view
|
||||
ForEach(thread.childEvents, id: \.id) { event in
|
||||
EventView(
|
||||
event: event,
|
||||
highlight: .none,
|
||||
has_action_bar: true,
|
||||
damus: damus,
|
||||
show_friend_icon: true, // TODO: change it
|
||||
size: .small
|
||||
damus: damus
|
||||
)
|
||||
.onTapGesture {
|
||||
nav_target = event.id
|
||||
|
||||
@@ -43,7 +43,7 @@ struct InnerTimelineView: View {
|
||||
//let is_chatroom = should_show_chatroom(ev)
|
||||
//let tv = ThreadView(thread: tm, damus: damus, is_chatroom: is_chatroom)
|
||||
|
||||
EventView(event: ev, highlight: .none, has_action_bar: true, damus: damus, show_friend_icon: show_friend_icon)
|
||||
EventView(event: ev, has_action_bar: true, damus: damus)
|
||||
.onTapGesture {
|
||||
nav_target = ev
|
||||
navigating = true
|
||||
@@ -52,6 +52,7 @@ struct InnerTimelineView: View {
|
||||
}
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.padding(.top,10)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
9
damus/de-AT.lproj/InfoPlist.strings
Normal file
9
damus/de-AT.lproj/InfoPlist.strings
Normal file
@@ -0,0 +1,9 @@
|
||||
/* Bundle display name */
|
||||
"CFBundleDisplayName" = "Damus";
|
||||
|
||||
/* Bundle name */
|
||||
"CFBundleName" = "damus";
|
||||
|
||||
/* Privacy - Photo Library Additions Usage Description */
|
||||
"NSPhotoLibraryAddUsageDescription" = "Damus Zugriff auf deine Fotos zu gewähren erlaubt dir Bilder zu sichern.";
|
||||
|
||||
499
damus/de-AT.lproj/Localizable.strings
Normal file
499
damus/de-AT.lproj/Localizable.strings
Normal file
@@ -0,0 +1,499 @@
|
||||
/* Blank space to separate profile picture from profile editor form. */
|
||||
" " = "61b6edf1108e6f396680a33b02486a70_tr";
|
||||
|
||||
/* Description of how the nip05 identifier would be used for verification. */
|
||||
"'%@' at '%@' will be used for verification" = "'%@' bei '%@' wird zur Verifizierung benutzt werden.";
|
||||
|
||||
/* Description of why the nip05 identifier is invalid. */
|
||||
"'%@' is an invalid nip05 identifier. It should look like an email." = "'%@' ist eine ungültige nip05 Kennzeichnung. Diese sollte wie eine Emailadresse aussehen. ";
|
||||
|
||||
/* Navigation bar title for view that shows who is following a user. */
|
||||
"(Profile.displayName(profile: profile, pubkey: whos))'s Followers" = "(Profile.displayName(profile: profile, pubkey: whos)) Follower";
|
||||
|
||||
/* Navigation bar title for view that shows who a user is following. */
|
||||
"(who) following" = "(who) folgt";
|
||||
|
||||
/* Prefix character to username. */
|
||||
"@" = "@";
|
||||
|
||||
/* Amount of time that has passed since reply quote event occurred.
|
||||
Abbreviated version of a nostr public key. */
|
||||
"%@" = "%@";
|
||||
|
||||
/* 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'. */
|
||||
"%@ %@" = "%@ %@";
|
||||
|
||||
/* Explanation of what is done to keep personally identifiable information private. There is a heading that precedes this explanation which is a variable to this string. */
|
||||
"%@. Creating an account doesn't require a phone number, email or name. Get started right away with zero friction." = "%@. Ein Konto zu erstellen benötigt keine Telefonnummer, Emailadresse oder Namen. Fang jetzt gleich ganz reibungslos an.";
|
||||
|
||||
/* Explanation of what is done to keep private data encrypted. There is a heading that precedes this explanation which is a variable to this string. */
|
||||
"%@. End-to-End encrypted private messaging. Keep Big Tech out of your DMs" = "%@. End-zu-End verschlüsselter privater Nachrichtenaustausch. Halte Tech-Riesen aus deinen PNs heraus";
|
||||
|
||||
/* Explanation of what can be done by users to earn money. There is a heading that precedes this explanation which is a variable to this string. */
|
||||
"%@. Tip your friend's posts and stack sats with Bitcoin⚡️, the native currency of the internet." = "%@. Belohne Beiträge deiner Freunde und sammle Sats mit Bitcoin⚡️, der eigenen Währung des Internets.";
|
||||
|
||||
/* Number of reposts.
|
||||
Number of profiles a user is following. */
|
||||
"%lld" = "%lld";
|
||||
|
||||
/* Fraction of how many of the user's relay servers that are operational. */
|
||||
"%lld/%lld" = "%lld/%lld";
|
||||
|
||||
/* Placeholder for event mention. */
|
||||
"< e >" = "< e >";
|
||||
|
||||
/* Label to prompt for about text entry for user to describe about themself. */
|
||||
"About" = "Über";
|
||||
|
||||
/* Label for About Me section of user profile form. */
|
||||
"About Me" = "Über mich";
|
||||
|
||||
/* Placeholder text for About Me description. */
|
||||
"Absolute Boss" = "Absoluter Macher";
|
||||
|
||||
/* Label to indicate the public ID of the account. */
|
||||
"Account ID" = "Konto ID";
|
||||
|
||||
/* Button to add recommended relay server.
|
||||
Button to confirm adding user inputted relay. */
|
||||
"Add" = "Hinzufügen";
|
||||
|
||||
/* Label for section for adding a relay server. */
|
||||
"Add Relay" = "Relay hinzufügen";
|
||||
|
||||
/* Any amount of sats */
|
||||
"Any" = "beliebig";
|
||||
|
||||
/* Alert message to ask if user wants to repost a post. */
|
||||
"Are you sure you want to repost this?" = "Bist du sicher dass Du den Beitrag auf deinem Profil teilen möchtest?";
|
||||
|
||||
/* Label for Banner Image section of user profile form. */
|
||||
"Banner Image" = "Bannerbild";
|
||||
|
||||
/* Reminder to user that they should save their account information. */
|
||||
"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." = "Bevor wir anfangen, Du wirst deine Kontodaten sichern müssen, sonst wirst du dich in der Zukunft nicht mehr anmelden können wenn du Damus jemals deinstallierst.";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Bitcoin Beach. */
|
||||
"Bitcoin Beach" = "Bitcoin Beach";
|
||||
|
||||
/* Label for Bitcoin Lightning Tips section of user profile form. */
|
||||
"Bitcoin Lightning Tips" = "Bitcoin Lightning Zahlungen";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Blixt Wallet */
|
||||
"Blixt Wallet" = "Blixt Wallet";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Blue Wallet. */
|
||||
"Blue Wallet" = "Blue Wallet";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Breez. */
|
||||
"Breez" = "Breez";
|
||||
|
||||
/* Context menu option for broadcasting the user's note to all of the user's connected relay servers. */
|
||||
"Broadcast" = "Senden";
|
||||
|
||||
/* 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. */
|
||||
"Cancel" = "Abbrechen";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Cash App. */
|
||||
"Cash App" = "Cash App";
|
||||
|
||||
/* Navigation bar title for Chatroom view. */
|
||||
"Chat" = "Unterhaltungen";
|
||||
|
||||
/* Button for clearing cached data. */
|
||||
"Clear" = "Löschen";
|
||||
|
||||
/* Section title for clearing cached data. */
|
||||
"Clear Cache" = "Zwischenspeicher löschen";
|
||||
|
||||
/* Label indicating that a user's key was copied. */
|
||||
"Copied" = "Kopiert";
|
||||
|
||||
/* Button to copy a relay server address. */
|
||||
"Copy" = "Kopieren";
|
||||
|
||||
/* Context menu option for copying the ID of the account that created the note. */
|
||||
"Copy Account ID" = "Konto ID kopieren";
|
||||
|
||||
/* Context menu option to copy an image into clipboard.
|
||||
Context menu option to copy an image to clipboard. */
|
||||
"Copy Image" = "Bild kopieren";
|
||||
|
||||
/* Context menu option to copy the URL of an image into clipboard. */
|
||||
"Copy Image URL" = "Bild URL kopieren";
|
||||
|
||||
/* Title of section for copying a Lightning invoice identifier. */
|
||||
"Copy invoice" = "Zahlungsdaten kopieren";
|
||||
|
||||
/* Context menu option for copying a user's Lightning URL. */
|
||||
"Copy LNURL" = "LNURL kopieren";
|
||||
|
||||
/* Context menu option for copying the ID of the note. */
|
||||
"Copy Note ID" = "Notiz ID kopieren";
|
||||
|
||||
/* Context menu option for copying the JSON text from the note. */
|
||||
"Copy Note JSON" = "Notiz JSON kopieren";
|
||||
|
||||
/* Context menu option for copying the text from an note. */
|
||||
"Copy Text" = "Text kopieren";
|
||||
|
||||
/* Context menu option for copying the ID of the user who created the note. */
|
||||
"Copy User ID" = "Benutzer ID kopieren";
|
||||
|
||||
/* Button to create account. */
|
||||
"Create" = "Erstellen";
|
||||
|
||||
/* Button to create an account. */
|
||||
"Create Account" = "Konto erstellen";
|
||||
|
||||
/* Example description about Bitcoin creator(s), Satoshi Nakamoto. */
|
||||
"Creator(s) of Bitcoin. Absolute legend." = "Erfinder von Bitcoin. Absolute Legende(n).";
|
||||
|
||||
/* Name of the app, shown on the first screen when user is not logged in. */
|
||||
"Damus" = "Damus";
|
||||
|
||||
/* Button to pay a Lightning invoice with the user's default Lightning wallet. */
|
||||
"Default Wallet" = "Voreingestelltes Wallet";
|
||||
|
||||
/* Button to delete a relay server that the user connects to. */
|
||||
"Delete" = "Löschen";
|
||||
|
||||
/* Button to dismiss a text field alert. */
|
||||
"Dismiss" = "Schließen";
|
||||
|
||||
/* Label to prompt display name entry. */
|
||||
"Display Name" = "Profilname";
|
||||
|
||||
/* Navigation title for DM view, which is the English abbreviation for Direct Message. */
|
||||
"DM" = "PN";
|
||||
|
||||
/* DM selector for seeing either DMs or message requests, which are messages that have not been responded to yet. */
|
||||
"DM Type" = "PN Typ";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"DMs" = "PNs";
|
||||
|
||||
/* Button to dismiss wallet selection view for paying Lightning invoice. */
|
||||
"Done" = "Fertig";
|
||||
|
||||
/* Heading indicating that this application allows users to earn money. */
|
||||
"Earn Money" = "Verdiene Geld";
|
||||
|
||||
/* Button to edit user's profile. */
|
||||
"Edit" = "Bearbeiten";
|
||||
|
||||
/* Heading indicating that this application keeps private messaging end-to-end encrypted. */
|
||||
"Encrypted" = "Verschlüsselt";
|
||||
|
||||
/* Navigation title for view of encrypted DMs, where DM is an English abbreviation for Direct Message. */
|
||||
"Encrypted DMs" = "Verschlüsselte PNs";
|
||||
|
||||
/* Prompt for user to enter an account key to login. */
|
||||
"Enter your account key to login:" = "Gib deinen Kontoschlüssel ein um dich anzumelden:";
|
||||
|
||||
/* Error message indicating why saving keys failed. */
|
||||
"Error: %@" = "Fehler: %@";
|
||||
|
||||
/* Filter state for seeing either only posts, or posts & replies. */
|
||||
"Filter State" = "Filter Einstellung";
|
||||
|
||||
/* Button to follow a user. */
|
||||
"Follow" = "Folgen";
|
||||
|
||||
/* Label describing followers of a user. */
|
||||
"Followers" = "Follower";
|
||||
|
||||
/* Text to indicate that the button next to it is in a state that indicates that it is in the process of following a profile.
|
||||
Part of a larger sentence to describe how many profiles a user is following. */
|
||||
"Following" = "Folgt";
|
||||
|
||||
/* Label to indicate that the user is in the process of following another user. */
|
||||
"Following..." = "Folge…";
|
||||
|
||||
/* Text to indicate that button next to it is in a state that will follow a profile when tapped. */
|
||||
"Follows" = "Folgt";
|
||||
|
||||
/* Navigation bar title for Global view where posts from all connected relay servers appear. */
|
||||
"Global" = "Weltweit";
|
||||
|
||||
/* Navigation link to go to post referenced by hex code. */
|
||||
"Goto post %@" = "Gehe zum Beitrag %@";
|
||||
|
||||
/* Navigation link to go to profile. */
|
||||
"Goto profile %@" = "Gehe zum Profil %@";
|
||||
|
||||
/* Navigation bar title for Home view where posts and replies appear from those who the user is following. */
|
||||
"Home" = "Heim";
|
||||
|
||||
/* Placeholder example text for profile picture URL. */
|
||||
"https://example.com/pic.jpg" = "https://beispiel.at/bild.jpg";
|
||||
|
||||
/* Placeholder example text for website URL for user profile. */
|
||||
"https://jb55.com" = "https://jb55.com";
|
||||
|
||||
/* Error message indicating that an invalid account key was entered for login. */
|
||||
"Invalid key" = "Ungültiger Schlüssel";
|
||||
|
||||
/* Placeholder example text for identifier used for NIP-05 verification. */
|
||||
"jb55@jb55.com" = "jb55@jb55.com";
|
||||
|
||||
/* Moves the post button to the left side of the screen */
|
||||
"Left Handed" = "Linkshändig";
|
||||
|
||||
/* Button to complete account creation and start using the app. */
|
||||
"Let's go!" = "Lass uns loslegen!";
|
||||
|
||||
/* Placeholder text for entry of Lightning Address or LNURL. */
|
||||
"Lightning Address or LNURL" = "Lightning-Adresse oder LNURL";
|
||||
|
||||
/* Indicates that the view is for paying a Lightning invoice. */
|
||||
"Lightning Invoice" = "Lightning-Rechnung";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, LNLink. */
|
||||
"LNLink" = "LNLink";
|
||||
|
||||
/* Dropdown option label for system default for Lightning wallet. */
|
||||
"Local default" = "System-Standard";
|
||||
|
||||
/* Button to log into account.
|
||||
Button to log into an account. */
|
||||
"Login" = "Einloggen";
|
||||
|
||||
/* Alert for logging out the user.
|
||||
Button for logging out the user.
|
||||
Button to logout the user. */
|
||||
"Logout" = "Ausloggen";
|
||||
|
||||
/* Reminder message in alert to get customer to verify that their private security account key is saved saved before logging out. */
|
||||
"Make sure your nsec account key is saved before you logout or you will lose access to this account" = "Stelle sicher, dass du deinen nsec-Schlüssel gespeichert hast, sonst wirst du den Zugang zu deinem Konto verlieren.";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Muun. */
|
||||
"Muun" = "Muun";
|
||||
|
||||
/* Label for NIP-05 Verification section of user profile form. */
|
||||
"NIP-05 Verification" = "NIP-05-Verifizierung";
|
||||
|
||||
/* No search results. */
|
||||
"none" = "keine";
|
||||
|
||||
/* Indicates that there are no notes in the timeline to view. */
|
||||
"Nothing to see here. Check back later!" = "Hier gibt es nichts zu sehen. Komm später wieder vorbei!";
|
||||
|
||||
/* Navigation title for notifications. */
|
||||
"Notifications" = "Benachrichtigungen";
|
||||
|
||||
/* String indicating that a given timestamp just occurred */
|
||||
"now" = "jetzt";
|
||||
|
||||
/* Prompt for user to enter in an account key to login. This text shows the characters the key could start with if it was a private key. */
|
||||
"nsec1..." = "nsec1...";
|
||||
|
||||
/* Label indicating that a form input is optional. */
|
||||
"optional" = "optional";
|
||||
|
||||
/* Button to pay a Lightning invoice. */
|
||||
"Pay" = "Bezahlen";
|
||||
|
||||
/* Navigation bar title for view to pay Lightning invoice. */
|
||||
"Pay the Lightning invoice" = "Bezahle die Lightning-Rechnung";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Phoenix. */
|
||||
"Phoenix" = "Phoenix";
|
||||
|
||||
/* Button to post a note. */
|
||||
"Post" = "Veröffentlichen";
|
||||
|
||||
/* Label for filter for seeing only posts (instead of posts and replies). */
|
||||
"Posts" = "Beiträge";
|
||||
|
||||
/* Label for filter for seeing posts and replies (instead of only posts). */
|
||||
"Posts & Replies" = "Beiträge & Antworten";
|
||||
|
||||
/* Heading indicating that this application keeps personally identifiable information private. A sentence describing what is done to keep data private comes after this heading. */
|
||||
"Private" = "Privat";
|
||||
|
||||
/* Title of the secure field that holds the user's private key. */
|
||||
"Private Key" = "Privater Schlüssel";
|
||||
|
||||
/* Sidebar menu label for Profile view. */
|
||||
"Profile" = "Profil";
|
||||
|
||||
/* Label for Profile Picture section of user profile form. */
|
||||
"Profile Picture" = "Profilbild";
|
||||
|
||||
/* Section title for the user's public account ID. */
|
||||
"Public Account ID" = "Öffentliche Konto ID";
|
||||
|
||||
/* Label indicating that the text is a user's public account key. */
|
||||
"Public key" = "Öffentlicher Schlüssel";
|
||||
|
||||
/* Label indicating that the text is a user's public account key. */
|
||||
"Public Key" = "Öffentlicher Schlüssel";
|
||||
|
||||
/* Prompt to ask user if the key they entered is a public key. */
|
||||
"Public Key?" = "Öffentlicher Schlüssel?";
|
||||
|
||||
/* Navigation bar title for Reactions view. */
|
||||
"Reactions" = "Reaktionen";
|
||||
|
||||
/* Section title for recommend relay servers that could be added as part of configuration */
|
||||
"Recommended Relays" = "Empfohlene Relays";
|
||||
|
||||
/* Text field for relay server. Used for testing purposes. */
|
||||
"Relay" = "Relay";
|
||||
|
||||
/* Sidebar menu label for Relay servers view */
|
||||
"Relays" = "Relays";
|
||||
|
||||
/* Label to indicate that the user is replying to themself. */
|
||||
"Reply to self" = "Antwort an sich selbst";
|
||||
|
||||
/* Label to indicate that the user is replying to 2 users. */
|
||||
"Replying to %@ & %@" = "Antwort an %1$@ & %2$@";
|
||||
|
||||
/* Indicating that the user is replying to the following listed people. */
|
||||
"Replying to:" = "Antwort an:";
|
||||
|
||||
/* Button to confirm reposting a post.
|
||||
Title of alert for confirming to repost a post. */
|
||||
"Repost" = "Selbst teilen";
|
||||
|
||||
/* Text indicating that the post was reposted (i.e. re-shared). */
|
||||
"Reposted" = "Selbst geteilt";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Requests" = "Anfragen";
|
||||
|
||||
/* Section title for resetting the user */
|
||||
"Reset" = "Zurücksetzen";
|
||||
|
||||
/* Button to retry completing account creation after an error occurred. */
|
||||
"Retry" = "Erneut versuchen";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, River */
|
||||
"River" = "River";
|
||||
|
||||
/* Example username of Bitcoin creator(s), Satoshi Nakamoto. */
|
||||
"satoshi" = "satoshi";
|
||||
|
||||
/* Name of Bitcoin creator(s). */
|
||||
"Satoshi Nakamoto" = "Satoshi Nakamoto";
|
||||
|
||||
/* Button for saving profile. */
|
||||
"Save" = "Speichern";
|
||||
|
||||
/* Context menu option to save an image. */
|
||||
"Save Image" = "Bild sichern";
|
||||
|
||||
/* Navigation link to search hashtag. */
|
||||
"Search hashtag: #%@" = "Hashtag suchen: #%@";
|
||||
|
||||
/* Placeholder text to prompt entry of search query. */
|
||||
"Search..." = "Suchen...";
|
||||
|
||||
/* Section title for user's secret account login key. */
|
||||
"Secret Account Login Key" = "Geheimer Konto Anmeldeschlüssel";
|
||||
|
||||
/* Title of section for selecting a Lightning wallet to pay a Lightning invoice. */
|
||||
"Select a Lightning wallet" = "Wähle ein Lightning Wallet";
|
||||
|
||||
/* Prompt selection of user's default wallet */
|
||||
"Select default wallet" = "Wähle das voreingestellte Wallet";
|
||||
|
||||
/* Text prompt for user to send a message to the other user. */
|
||||
"Send a message to start the conversation..." = "Sende eine Nachricht um eine Unterhaltung zu beginnen...";
|
||||
|
||||
/* Navigation title for Settings view.
|
||||
Sidebar menu label for accessing the app settings */
|
||||
"Settings" = "Einstellungen";
|
||||
|
||||
/* Button to share an image. */
|
||||
"Share" = "Teilen";
|
||||
|
||||
/* Toggle to show or hide user's secret account login key. */
|
||||
"Show" = "Anzeigen";
|
||||
|
||||
/* Toggle to show or hide selection of wallet. */
|
||||
"Show wallet selector" = "Wallet-Auswahl zeigen";
|
||||
|
||||
/* Sidebar menu label to sign out of the account. */
|
||||
"Sign out" = "Abmelden";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Strike. */
|
||||
"Strike" = "Strike";
|
||||
|
||||
/* Warning that the inputted account key is a public key and the result of what happens because of it. */
|
||||
"This is a public key, you will not be able to make posts or interact in any way. This is used for viewing accounts from their perspective." = "Dies ist ein öffentlicher Schlüssel, mit dem Sie keine Beiträge verfassen oder in irgendeiner Weise interagieren können. Er wird verwendet, um Konten aus deren Perspektive zu betrachten.";
|
||||
|
||||
/* Warning that the inputted account key for login is an old-style and asking user to verify if it is a public key. */
|
||||
"This is an old-style nostr key. We're not sure if it's a pubkey or private key. Please toggle the button below if this a public key." = "Dies ist ein Nostr-Schlüssel im alten Format. Es ist nicht eindeutig, ob es ein öffentlicher oder privater Schlüssel ist. Bitte aktiviere die Schaltfläche unten, wenn es ein öffentlicher Schlüssel ist.";
|
||||
|
||||
/* Label to describe that a public key is the user's account ID and what they can do with it. */
|
||||
"This is your account ID, you can give this to your friends so that they can follow you. Click to copy." = "Dies ist deine Konto-ID, die du an deine Freunde weitergeben kannst, damit sie dir folgen können. Zum Kopieren anklicken.";
|
||||
|
||||
/* Label to describe that a private key is the user's secret account key and what they should do with it. */
|
||||
"This is your secret account key. You need this to access your account. Don't share this with anyone! Save it in a password manager and keep it safe!" = "Dies ist dein geheimer, privater Schlüssel. Du benötigst ihn, um auf dein Konto zuzugreifen. Gib den privaten Schlüssel an niemanden weiter! Speichere ihn in einem Passwort-Manager und bewahre ihn sicher auf!";
|
||||
|
||||
/* Navigation bar title for note thread.
|
||||
Navigation bar title for threaded event detail view. */
|
||||
"Thread" = "Thema";
|
||||
|
||||
/* Text box prompt to ask user to type their post. */
|
||||
"Type your post here..." = "Schreibe deinen Beitrag hier...";
|
||||
|
||||
/* Non-breaking space character to fill in blank space next to event action button icons. */
|
||||
"u{00A0}" = "u{00A0}";
|
||||
|
||||
/* Button to unfollow a user. */
|
||||
"Unfollow" = "Entfolgen";
|
||||
|
||||
/* Text to indicate that the button next to it is in a state that indicates that it is in the process of unfollowing a profile. */
|
||||
"Unfollowing" = "Entfolgen...";
|
||||
|
||||
/* Label to indicate that the user is in the process of unfollowing another user. */
|
||||
"Unfollowing..." = "Entfolgen...";
|
||||
|
||||
/* Text to indicate that the button next to it is in a state that will unfollow a profile when tapped. */
|
||||
"Unfollows" = "Entfolgen";
|
||||
|
||||
/* Label for Username section of user profile form.
|
||||
Label to prompt username entry. */
|
||||
"Username" = "Benutzername";
|
||||
|
||||
/* Sidebar menu label for Wallet view. */
|
||||
"Wallet" = "Wallet";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Wallet Of Satoshi. */
|
||||
"Wallet Of Satoshi" = "Wallet Of Satoshi";
|
||||
|
||||
/* Section title for selection of wallet. */
|
||||
"Wallet Selector" = "Wallet-Auswahl";
|
||||
|
||||
/* Label for Website section of user profile form. */
|
||||
"Website" = "Website";
|
||||
|
||||
/* Welcoming message to the reader. The variable is 'you', the reader. */
|
||||
"Welcome to the social network %@ control." = "Willkommen in dem sozialen Netzwerk das %@ kontrollierst.";
|
||||
|
||||
/* Text to welcome user. */
|
||||
"Welcome, %@!" = "Willkommen, %@!";
|
||||
|
||||
/* Placeholder example for relay server address. */
|
||||
"wss://some.relay.com" = "wss://ein.relay.at";
|
||||
|
||||
/* 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. */
|
||||
"you" = "Du";
|
||||
|
||||
/* Label for Your Name section of user profile form. */
|
||||
"Your Name" = "Dein Name";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Zebedee. */
|
||||
"Zebedee" = "Zebedee";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Zeus LN. */
|
||||
"Zeus LN" = "Zeus LN";
|
||||
|
||||
154
damus/de-AT.lproj/Localizable.stringsdict
Normal file
154
damus/de-AT.lproj/Localizable.stringsdict
Normal file
@@ -0,0 +1,154 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>collapsed_event_view_other_notes</key>
|
||||
<dict>
|
||||
<key>NOTES</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>1%d andere Notiz</string>
|
||||
<key>other</key>
|
||||
<string>1%d andere Notizen</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>··· %#@NOTES@ ···</string>
|
||||
</dict>
|
||||
<key>followers_count</key>
|
||||
<dict>
|
||||
<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>Follower</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@FOLLOWERS@</string>
|
||||
</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>Reaktion</string>
|
||||
<key>other</key>
|
||||
<string>Reaktionen</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>
|
||||
<string>Antwort an %@%#@OTHERS@</string>
|
||||
<key>OTHERS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>& 1%d andere</string>
|
||||
<key>other</key>
|
||||
<string>& %d andere</string>
|
||||
<key>zero</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>replying_to_two_and_others</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>Antwort an %@, %@%#@OTHERS@</string>
|
||||
<key>OTHERS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>& %d andere</string>
|
||||
<key>other</key>
|
||||
<string>& %d andere</string>
|
||||
<key>zero</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>reposts_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@REPOSTS@</string>
|
||||
<key>REPOSTS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>geteilter Beitrag</string>
|
||||
<key>other</key>
|
||||
<string>geteilte Beiträge</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>Trinkgeld</string>
|
||||
<key>other</key>
|
||||
<string>Trinkgelder</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
9
damus/de-DE.lproj/InfoPlist.strings
Normal file
9
damus/de-DE.lproj/InfoPlist.strings
Normal file
@@ -0,0 +1,9 @@
|
||||
/* Bundle display name */
|
||||
"CFBundleDisplayName" = "Damus";
|
||||
|
||||
/* Bundle name */
|
||||
"CFBundleName" = "damus";
|
||||
|
||||
/* Privacy - Photo Library Additions Usage Description */
|
||||
"NSPhotoLibraryAddUsageDescription" = "Damus Zugriff auf deine Fotos zu gewähren erlaubt dir Bilder zu sichern.";
|
||||
|
||||
499
damus/de-DE.lproj/Localizable.strings
Normal file
499
damus/de-DE.lproj/Localizable.strings
Normal file
@@ -0,0 +1,499 @@
|
||||
/* Blank space to separate profile picture from profile editor form. */
|
||||
" " = "61b6edf1108e6f396680a33b02486a70_tr";
|
||||
|
||||
/* Description of how the nip05 identifier would be used for verification. */
|
||||
"'%@' at '%@' will be used for verification" = "'%@' bei '%@' wird zur Verifizierung benutzt werden.";
|
||||
|
||||
/* Description of why the nip05 identifier is invalid. */
|
||||
"'%@' is an invalid nip05 identifier. It should look like an email." = "'%@' ist eine ungültige nip05 Kennzeichnung. Diese sollte wie eine Emailadresse aussehen. ";
|
||||
|
||||
/* Navigation bar title for view that shows who is following a user. */
|
||||
"(Profile.displayName(profile: profile, pubkey: whos))'s Followers" = "(Profile.displayName(profile: profile, pubkey: whos)) Follower";
|
||||
|
||||
/* Navigation bar title for view that shows who a user is following. */
|
||||
"(who) following" = "(who) folgt";
|
||||
|
||||
/* Prefix character to username. */
|
||||
"@" = "@";
|
||||
|
||||
/* Amount of time that has passed since reply quote event occurred.
|
||||
Abbreviated version of a nostr public key. */
|
||||
"%@" = "%@";
|
||||
|
||||
/* 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'. */
|
||||
"%@ %@" = "%@ %@";
|
||||
|
||||
/* Explanation of what is done to keep personally identifiable information private. There is a heading that precedes this explanation which is a variable to this string. */
|
||||
"%@. Creating an account doesn't require a phone number, email or name. Get started right away with zero friction." = "Für das Erstellen eines Accounts ist keine Telefonnumer, E-Mail-Adresse und kein Name notwendig. Lege direkt los!";
|
||||
|
||||
/* Explanation of what is done to keep private data encrypted. There is a heading that precedes this explanation which is a variable to this string. */
|
||||
"%@. End-to-End encrypted private messaging. Keep Big Tech out of your DMs" = "%@. Ende-zu-Ende verschlüsselte private Nachrichten. Halte „Big Tech“ aus deinen Direktnachrichten heraus.";
|
||||
|
||||
/* Explanation of what can be done by users to earn money. There is a heading that precedes this explanation which is a variable to this string. */
|
||||
"%@. Tip your friend's posts and stack sats with Bitcoin⚡️, the native currency of the internet." = "%@. Belohne Beiträge deiner Freunde und sammle Sats mit Bitcoin⚡️, der eigenen Währung des Internets.";
|
||||
|
||||
/* Number of reposts.
|
||||
Number of profiles a user is following. */
|
||||
"%lld" = "%lld";
|
||||
|
||||
/* Fraction of how many of the user's relay servers that are operational. */
|
||||
"%lld/%lld" = "%lld/%lld";
|
||||
|
||||
/* Placeholder for event mention. */
|
||||
"< e >" = "< e >";
|
||||
|
||||
/* Label to prompt for about text entry for user to describe about themself. */
|
||||
"About" = "Über";
|
||||
|
||||
/* Label for About Me section of user profile form. */
|
||||
"About Me" = "Über mich";
|
||||
|
||||
/* Placeholder text for About Me description. */
|
||||
"Absolute Boss" = "Absoluter Macher";
|
||||
|
||||
/* Label to indicate the public ID of the account. */
|
||||
"Account ID" = "Konto-ID";
|
||||
|
||||
/* Button to add recommended relay server.
|
||||
Button to confirm adding user inputted relay. */
|
||||
"Add" = "Hinzufügen";
|
||||
|
||||
/* Label for section for adding a relay server. */
|
||||
"Add Relay" = "Relay hinzufügen";
|
||||
|
||||
/* Any amount of sats */
|
||||
"Any" = "beliebig";
|
||||
|
||||
/* Alert message to ask if user wants to repost a post. */
|
||||
"Are you sure you want to repost this?" = "Bist du sicher dass Du den Beitrag auf deinem Profil teilen möchtest?";
|
||||
|
||||
/* Label for Banner Image section of user profile form. */
|
||||
"Banner Image" = "Banner Bild";
|
||||
|
||||
/* Reminder to user that they should save their account information. */
|
||||
"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." = "Bevor wir anfangen, musst du deine Kontodaten sichern, sonst kannst du dich in Zukunft nicht mehr anmelden, wenn du Damus jemals deinstallierst.";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Bitcoin Beach. */
|
||||
"Bitcoin Beach" = "Bitcoin Beach";
|
||||
|
||||
/* Label for Bitcoin Lightning Tips section of user profile form. */
|
||||
"Bitcoin Lightning Tips" = "Bitcoin Lightning Zahlungen";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Blixt Wallet */
|
||||
"Blixt Wallet" = "Blixt Wallet";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Blue Wallet. */
|
||||
"Blue Wallet" = "Blue Wallet";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Breez. */
|
||||
"Breez" = "Breez";
|
||||
|
||||
/* Context menu option for broadcasting the user's note to all of the user's connected relay servers. */
|
||||
"Broadcast" = "Senden";
|
||||
|
||||
/* 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. */
|
||||
"Cancel" = "Abbrechen";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Cash App. */
|
||||
"Cash App" = "Cash App";
|
||||
|
||||
/* Navigation bar title for Chatroom view. */
|
||||
"Chat" = "Unterhaltung";
|
||||
|
||||
/* Button for clearing cached data. */
|
||||
"Clear" = "Löschen";
|
||||
|
||||
/* Section title for clearing cached data. */
|
||||
"Clear Cache" = "Zwischenspeicher löschen";
|
||||
|
||||
/* Label indicating that a user's key was copied. */
|
||||
"Copied" = "Kopiert";
|
||||
|
||||
/* Button to copy a relay server address. */
|
||||
"Copy" = "Kopieren";
|
||||
|
||||
/* Context menu option for copying the ID of the account that created the note. */
|
||||
"Copy Account ID" = "Konto-ID kopieren";
|
||||
|
||||
/* Context menu option to copy an image into clipboard.
|
||||
Context menu option to copy an image to clipboard. */
|
||||
"Copy Image" = "Bild kopieren";
|
||||
|
||||
/* Context menu option to copy the URL of an image into clipboard. */
|
||||
"Copy Image URL" = "Bild-URL kopieren";
|
||||
|
||||
/* Title of section for copying a Lightning invoice identifier. */
|
||||
"Copy invoice" = "Rechnung kopieren";
|
||||
|
||||
/* Context menu option for copying a user's Lightning URL. */
|
||||
"Copy LNURL" = "LNURL kopieren";
|
||||
|
||||
/* Context menu option for copying the ID of the note. */
|
||||
"Copy Note ID" = "Notiz-ID kopieren";
|
||||
|
||||
/* Context menu option for copying the JSON text from the note. */
|
||||
"Copy Note JSON" = "Notiz-JSON kopieren";
|
||||
|
||||
/* Context menu option for copying the text from an note. */
|
||||
"Copy Text" = "Text kopieren";
|
||||
|
||||
/* Context menu option for copying the ID of the user who created the note. */
|
||||
"Copy User ID" = "Benutzer-ID kopieren";
|
||||
|
||||
/* Button to create account. */
|
||||
"Create" = "Erstellen";
|
||||
|
||||
/* Button to create an account. */
|
||||
"Create Account" = "Konto erstellen";
|
||||
|
||||
/* Example description about Bitcoin creator(s), Satoshi Nakamoto. */
|
||||
"Creator(s) of Bitcoin. Absolute legend." = "Erfinder von Bitcoin. Absolute Legende(n).";
|
||||
|
||||
/* Name of the app, shown on the first screen when user is not logged in. */
|
||||
"Damus" = "Damus";
|
||||
|
||||
/* Button to pay a Lightning invoice with the user's default Lightning wallet. */
|
||||
"Default Wallet" = "Voreingestellte Wallet";
|
||||
|
||||
/* Button to delete a relay server that the user connects to. */
|
||||
"Delete" = "Löschen";
|
||||
|
||||
/* Button to dismiss a text field alert. */
|
||||
"Dismiss" = "Schließen";
|
||||
|
||||
/* Label to prompt display name entry. */
|
||||
"Display Name" = "Profilname";
|
||||
|
||||
/* Navigation title for DM view, which is the English abbreviation for Direct Message. */
|
||||
"DM" = "PN";
|
||||
|
||||
/* DM selector for seeing either DMs or message requests, which are messages that have not been responded to yet. */
|
||||
"DM Type" = "PN Art";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"DMs" = "PNs";
|
||||
|
||||
/* Button to dismiss wallet selection view for paying Lightning invoice. */
|
||||
"Done" = "Fertig";
|
||||
|
||||
/* Heading indicating that this application allows users to earn money. */
|
||||
"Earn Money" = "Verdiene Geld";
|
||||
|
||||
/* Button to edit user's profile. */
|
||||
"Edit" = "Bearbeiten";
|
||||
|
||||
/* Heading indicating that this application keeps private messaging end-to-end encrypted. */
|
||||
"Encrypted" = "Verschlüsselt";
|
||||
|
||||
/* Navigation title for view of encrypted DMs, where DM is an English abbreviation for Direct Message. */
|
||||
"Encrypted DMs" = "Verschlüsselte PNs";
|
||||
|
||||
/* Prompt for user to enter an account key to login. */
|
||||
"Enter your account key to login:" = "Gib deinen Kontoschlüssel ein um dich anzumelden:";
|
||||
|
||||
/* Error message indicating why saving keys failed. */
|
||||
"Error: %@" = "Fehler: %@";
|
||||
|
||||
/* Filter state for seeing either only posts, or posts & replies. */
|
||||
"Filter State" = "Filter Einstellung";
|
||||
|
||||
/* Button to follow a user. */
|
||||
"Follow" = "Folgen";
|
||||
|
||||
/* Label describing followers of a user. */
|
||||
"Followers" = "Follower";
|
||||
|
||||
/* Text to indicate that the button next to it is in a state that indicates that it is in the process of following a profile.
|
||||
Part of a larger sentence to describe how many profiles a user is following. */
|
||||
"Following" = "Folgt";
|
||||
|
||||
/* Label to indicate that the user is in the process of following another user. */
|
||||
"Following..." = "Folge…";
|
||||
|
||||
/* Text to indicate that button next to it is in a state that will follow a profile when tapped. */
|
||||
"Follows" = "Folgt";
|
||||
|
||||
/* Navigation bar title for Global view where posts from all connected relay servers appear. */
|
||||
"Global" = "Weltweit";
|
||||
|
||||
/* Navigation link to go to post referenced by hex code. */
|
||||
"Goto post %@" = "Gehe zum Beitrag %@";
|
||||
|
||||
/* Navigation link to go to profile. */
|
||||
"Goto profile %@" = "Gehe zum Profil %@";
|
||||
|
||||
/* Navigation bar title for Home view where posts and replies appear from those who the user is following. */
|
||||
"Home" = "Heim";
|
||||
|
||||
/* Placeholder example text for profile picture URL. */
|
||||
"https://example.com/pic.jpg" = "https://beispiel.de/bild.jpg";
|
||||
|
||||
/* Placeholder example text for website URL for user profile. */
|
||||
"https://jb55.com" = "https://jb55.com";
|
||||
|
||||
/* Error message indicating that an invalid account key was entered for login. */
|
||||
"Invalid key" = "Ungültiger Schlüssel";
|
||||
|
||||
/* Placeholder example text for identifier used for NIP-05 verification. */
|
||||
"jb55@jb55.com" = "jb55@jb55.com";
|
||||
|
||||
/* Moves the post button to the left side of the screen */
|
||||
"Left Handed" = "Linkshändig";
|
||||
|
||||
/* Button to complete account creation and start using the app. */
|
||||
"Let's go!" = "Los gehts!";
|
||||
|
||||
/* Placeholder text for entry of Lightning Address or LNURL. */
|
||||
"Lightning Address or LNURL" = "Lightning-Adresse oder LNURL";
|
||||
|
||||
/* Indicates that the view is for paying a Lightning invoice. */
|
||||
"Lightning Invoice" = "Lightning-Rechnung";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, LNLink. */
|
||||
"LNLink" = "LNLink";
|
||||
|
||||
/* Dropdown option label for system default for Lightning wallet. */
|
||||
"Local default" = "System-Standard";
|
||||
|
||||
/* Button to log into account.
|
||||
Button to log into an account. */
|
||||
"Login" = "Anmelden";
|
||||
|
||||
/* Alert for logging out the user.
|
||||
Button for logging out the user.
|
||||
Button to logout the user. */
|
||||
"Logout" = "Abmelden";
|
||||
|
||||
/* Reminder message in alert to get customer to verify that their private security account key is saved saved before logging out. */
|
||||
"Make sure your nsec account key is saved before you logout or you will lose access to this account" = "Stelle sicher dass dein nsec Kontoschlüssel gesichert ist bevor du dich abmeldest oder du wirst den Zugang zu diesem Konto verlieren";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Muun. */
|
||||
"Muun" = "Muun";
|
||||
|
||||
/* Label for NIP-05 Verification section of user profile form. */
|
||||
"NIP-05 Verification" = "NIP-05-Verifizierung";
|
||||
|
||||
/* No search results. */
|
||||
"none" = "keine";
|
||||
|
||||
/* Indicates that there are no notes in the timeline to view. */
|
||||
"Nothing to see here. Check back later!" = "Hier gibts nichts zu sehen. Schau später wieder vorbei!";
|
||||
|
||||
/* Navigation title for notifications. */
|
||||
"Notifications" = "Benachrichtigungen";
|
||||
|
||||
/* String indicating that a given timestamp just occurred */
|
||||
"now" = "jetzt";
|
||||
|
||||
/* Prompt for user to enter in an account key to login. This text shows the characters the key could start with if it was a private key. */
|
||||
"nsec1..." = "nsec1...";
|
||||
|
||||
/* Label indicating that a form input is optional. */
|
||||
"optional" = "optional";
|
||||
|
||||
/* Button to pay a Lightning invoice. */
|
||||
"Pay" = "Bezahlen";
|
||||
|
||||
/* Navigation bar title for view to pay Lightning invoice. */
|
||||
"Pay the Lightning invoice" = "Bezahle die Lightning-Rechnung";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Phoenix. */
|
||||
"Phoenix" = "Phoenix";
|
||||
|
||||
/* Button to post a note. */
|
||||
"Post" = "Teilen";
|
||||
|
||||
/* Label for filter for seeing only posts (instead of posts and replies). */
|
||||
"Posts" = "Beiträge";
|
||||
|
||||
/* Label for filter for seeing posts and replies (instead of only posts). */
|
||||
"Posts & Replies" = "Beiträge & Antworten";
|
||||
|
||||
/* Heading indicating that this application keeps personally identifiable information private. A sentence describing what is done to keep data private comes after this heading. */
|
||||
"Private" = "Privatsphäre";
|
||||
|
||||
/* Title of the secure field that holds the user's private key. */
|
||||
"Private Key" = "Privater Schlüssel";
|
||||
|
||||
/* Sidebar menu label for Profile view. */
|
||||
"Profile" = "Profil";
|
||||
|
||||
/* Label for Profile Picture section of user profile form. */
|
||||
"Profile Picture" = "Profilbild";
|
||||
|
||||
/* Section title for the user's public account ID. */
|
||||
"Public Account ID" = "Öffentliche Konto ID";
|
||||
|
||||
/* Label indicating that the text is a user's public account key. */
|
||||
"Public key" = "Öffentlicher Schlüssel";
|
||||
|
||||
/* Label indicating that the text is a user's public account key. */
|
||||
"Public Key" = "Öffentlicher Schlüssel";
|
||||
|
||||
/* Prompt to ask user if the key they entered is a public key. */
|
||||
"Public Key?" = "Öffentlicher Schlüssel?";
|
||||
|
||||
/* Navigation bar title for Reactions view. */
|
||||
"Reactions" = "Reaktionen";
|
||||
|
||||
/* Section title for recommend relay servers that could be added as part of configuration */
|
||||
"Recommended Relays" = "Empfohlene Relays";
|
||||
|
||||
/* Text field for relay server. Used for testing purposes. */
|
||||
"Relay" = "Relay";
|
||||
|
||||
/* Sidebar menu label for Relay servers view */
|
||||
"Relays" = "Relays";
|
||||
|
||||
/* Label to indicate that the user is replying to themself. */
|
||||
"Reply to self" = "Antwort an dich selbst";
|
||||
|
||||
/* Label to indicate that the user is replying to 2 users. */
|
||||
"Replying to %@ & %@" = "%1$@ & %2$@ antworten";
|
||||
|
||||
/* Indicating that the user is replying to the following listed people. */
|
||||
"Replying to:" = "Du antwortest:";
|
||||
|
||||
/* Button to confirm reposting a post.
|
||||
Title of alert for confirming to repost a post. */
|
||||
"Repost" = "Teilen";
|
||||
|
||||
/* Text indicating that the post was reposted (i.e. re-shared). */
|
||||
"Reposted" = "Geteilt";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Requests" = "Anfragen";
|
||||
|
||||
/* Section title for resetting the user */
|
||||
"Reset" = "Zurücksetzen";
|
||||
|
||||
/* Button to retry completing account creation after an error occurred. */
|
||||
"Retry" = "Wiederholung";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, River */
|
||||
"River" = "River";
|
||||
|
||||
/* Example username of Bitcoin creator(s), Satoshi Nakamoto. */
|
||||
"satoshi" = "satoshi";
|
||||
|
||||
/* Name of Bitcoin creator(s). */
|
||||
"Satoshi Nakamoto" = "Satoshi Nakamoto";
|
||||
|
||||
/* Button for saving profile. */
|
||||
"Save" = "Speichern";
|
||||
|
||||
/* Context menu option to save an image. */
|
||||
"Save Image" = "Bild speichern";
|
||||
|
||||
/* Navigation link to search hashtag. */
|
||||
"Search hashtag: #%@" = "Hashtag suchen: #%@";
|
||||
|
||||
/* Placeholder text to prompt entry of search query. */
|
||||
"Search..." = "Suchen...";
|
||||
|
||||
/* Section title for user's secret account login key. */
|
||||
"Secret Account Login Key" = "Geheimer Konto-Anmeldeschlüssel";
|
||||
|
||||
/* Title of section for selecting a Lightning wallet to pay a Lightning invoice. */
|
||||
"Select a Lightning wallet" = "Wähle eine Lightning-Wallet";
|
||||
|
||||
/* Prompt selection of user's default wallet */
|
||||
"Select default wallet" = "Wähle ein voreingestelltes Wallet";
|
||||
|
||||
/* Text prompt for user to send a message to the other user. */
|
||||
"Send a message to start the conversation..." = "Sende eine Nachricht um die Unterhaltung zu beginnen...";
|
||||
|
||||
/* Navigation title for Settings view.
|
||||
Sidebar menu label for accessing the app settings */
|
||||
"Settings" = "Einstellungen";
|
||||
|
||||
/* Button to share an image. */
|
||||
"Share" = "Teilen";
|
||||
|
||||
/* Toggle to show or hide user's secret account login key. */
|
||||
"Show" = "Anzeigen";
|
||||
|
||||
/* Toggle to show or hide selection of wallet. */
|
||||
"Show wallet selector" = "Wallet-Auswahl anzeigen";
|
||||
|
||||
/* Sidebar menu label to sign out of the account. */
|
||||
"Sign out" = "Abmelden";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Strike. */
|
||||
"Strike" = "Strike";
|
||||
|
||||
/* Warning that the inputted account key is a public key and the result of what happens because of it. */
|
||||
"This is a public key, you will not be able to make posts or interact in any way. This is used for viewing accounts from their perspective." = "Dies ist ein öffentlicher Schlüssel, Du wirst keine Beiträge teilen oder oder auf irgendeine Weise interagieren können. Dies wird genutzt um Kontos aus deren Perspektive zu sehen.";
|
||||
|
||||
/* Warning that the inputted account key for login is an old-style and asking user to verify if it is a public key. */
|
||||
"This is an old-style nostr key. We're not sure if it's a pubkey or private key. Please toggle the button below if this a public key." = "Dies ist ein veralteter nostr-Schlüssel. Wir sind und unsicher ob es ein öffentlicher Schlüssel oder ein privater Schlüssel ist. Bitte betätige die untenstehende Schaltfläche wenn es ein öffentlicher Schlüssel ist.";
|
||||
|
||||
/* Label to describe that a public key is the user's account ID and what they can do with it. */
|
||||
"This is your account ID, you can give this to your friends so that they can follow you. Click to copy." = "Dies ist deine Konto-ID, die du an deine Freunde weitergeben kannst, damit sie dir folgen können. Zum Kopieren anklicken.";
|
||||
|
||||
/* Label to describe that a private key is the user's secret account key and what they should do with it. */
|
||||
"This is your secret account key. You need this to access your account. Don't share this with anyone! Save it in a password manager and keep it safe!" = "Dies ist dein geheimer, privater Schlüssel. Du benötigst ihn, um auf dein Konto zuzugreifen. Gib den privaten Schlüssel an niemanden weiter! Speichere ihn in einem Passwort-Manager und bewahre ihn sicher auf!";
|
||||
|
||||
/* Navigation bar title for note thread.
|
||||
Navigation bar title for threaded event detail view. */
|
||||
"Thread" = "Thema";
|
||||
|
||||
/* Text box prompt to ask user to type their post. */
|
||||
"Type your post here..." = "Schreibe deinen Beitrag hier...";
|
||||
|
||||
/* Non-breaking space character to fill in blank space next to event action button icons. */
|
||||
"u{00A0}" = "u{00A0}";
|
||||
|
||||
/* Button to unfollow a user. */
|
||||
"Unfollow" = "Entfolgen";
|
||||
|
||||
/* Text to indicate that the button next to it is in a state that indicates that it is in the process of unfollowing a profile. */
|
||||
"Unfollowing" = "Entfolgen...";
|
||||
|
||||
/* Label to indicate that the user is in the process of unfollowing another user. */
|
||||
"Unfollowing..." = "Entfolgen...";
|
||||
|
||||
/* Text to indicate that the button next to it is in a state that will unfollow a profile when tapped. */
|
||||
"Unfollows" = "Entfolgen";
|
||||
|
||||
/* Label for Username section of user profile form.
|
||||
Label to prompt username entry. */
|
||||
"Username" = "Benutzername";
|
||||
|
||||
/* Sidebar menu label for Wallet view. */
|
||||
"Wallet" = "Wallet";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Wallet Of Satoshi. */
|
||||
"Wallet Of Satoshi" = "Wallet Of Satoshi";
|
||||
|
||||
/* Section title for selection of wallet. */
|
||||
"Wallet Selector" = "Wallet-Auswahl";
|
||||
|
||||
/* Label for Website section of user profile form. */
|
||||
"Website" = "Website";
|
||||
|
||||
/* Welcoming message to the reader. The variable is 'you', the reader. */
|
||||
"Welcome to the social network %@ control." = "Willkommen in dem sozialen Netzwerk das %@ kontrollierst.";
|
||||
|
||||
/* Text to welcome user. */
|
||||
"Welcome, %@!" = "Willkommen, %@!";
|
||||
|
||||
/* Placeholder example for relay server address. */
|
||||
"wss://some.relay.com" = "wss://irgendein.relay.de";
|
||||
|
||||
/* 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. */
|
||||
"you" = "Du";
|
||||
|
||||
/* Label for Your Name section of user profile form. */
|
||||
"Your Name" = "Dein Name";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Zebedee. */
|
||||
"Zebedee" = "Zebedee";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Zeus LN. */
|
||||
"Zeus LN" = "Zeus LN";
|
||||
|
||||
154
damus/de-DE.lproj/Localizable.stringsdict
Normal file
154
damus/de-DE.lproj/Localizable.stringsdict
Normal file
@@ -0,0 +1,154 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>collapsed_event_view_other_notes</key>
|
||||
<dict>
|
||||
<key>NOTES</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%d andere Notiz</string>
|
||||
<key>other</key>
|
||||
<string>%d andere Notizen</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>··· %#@NOTES@ ···</string>
|
||||
</dict>
|
||||
<key>followers_count</key>
|
||||
<dict>
|
||||
<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>Follower</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@FOLLOWERS@</string>
|
||||
</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>Reaktion</string>
|
||||
<key>other</key>
|
||||
<string>Reaktionen</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>
|
||||
<string>Antwort an %@%#@OTHERS@</string>
|
||||
<key>OTHERS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>& %d andere</string>
|
||||
<key>other</key>
|
||||
<string>& %d andere</string>
|
||||
<key>zero</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>replying_to_two_and_others</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>Antwort an %@, %@%#@OTHERS@</string>
|
||||
<key>OTHERS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>& %d andere</string>
|
||||
<key>other</key>
|
||||
<string>& %d andere</string>
|
||||
<key>zero</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>reposts_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@REPOSTS@</string>
|
||||
<key>REPOSTS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Mal geteilt</string>
|
||||
<key>other</key>
|
||||
<string>Mal geteilt</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>Trinkgeld</string>
|
||||
<key>other</key>
|
||||
<string>Trinkgelder</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -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>
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
/* Bundle display name */
|
||||
"CFBundleDisplayName" = "Damus";
|
||||
|
||||
/* Bundle name */
|
||||
"CFBundleName" = "damus";
|
||||
|
||||
/* Privacy - Photo Library Additions Usage Description */
|
||||
"NSPhotoLibraryAddUsageDescription" = "\"Granting Damus access to your photo library allows you to save photos.";
|
||||
"NSPhotoLibraryAddUsageDescription" = "Si le concedes acceso a Damus a tu fototeca, podrás guardar fotos.";
|
||||
|
||||
493
damus/es-419.lproj/Localizable.strings
Normal file
493
damus/es-419.lproj/Localizable.strings
Normal file
@@ -0,0 +1,493 @@
|
||||
/* Blank space to separate profile picture from profile editor form. */
|
||||
" " = "61b6edf1108e6f396680a33b02486a70_tr";
|
||||
|
||||
/* Description of how the nip05 identifier would be used for verification. */
|
||||
"'%@' at '%@' will be used for verification" = "'%@' en '%@' se usarán con fines de verificación";
|
||||
|
||||
/* Description of why the nip05 identifier is invalid. */
|
||||
"'%@' is an invalid nip05 identifier. It should look like an email." = "'%@' es un identificador nip05 no válido. Debería de tener la apariencia de un correo electrónico.";
|
||||
|
||||
/* Navigation bar title for view that shows who is following a user. */
|
||||
"(Profile.displayName(profile: profile, pubkey: whos))'s Followers" = "Seguidores de (Profile.displayName(profile: profile, pubkey: whos))";
|
||||
|
||||
/* Navigation bar title for view that shows who a user is following. */
|
||||
"(who) following" = "(who) sigue a";
|
||||
|
||||
/* Prefix character to username. */
|
||||
"@" = "@";
|
||||
|
||||
/* Amount of time that has passed since reply quote event occurred.
|
||||
Abbreviated version of a nostr public key. */
|
||||
"%@" = "%@";
|
||||
|
||||
/* 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'. */
|
||||
"%@ %@" = "%@ %@";
|
||||
|
||||
/* Explanation of what is done to keep personally identifiable information private. There is a heading that precedes this explanation which is a variable to this string. */
|
||||
"%@. Creating an account doesn't require a phone number, email or name. Get started right away with zero friction." = "%@. No se requiere un número de teléfono, correo electrónico ni nombre para crear una cuenta. Comienza de inmediato sin fricciones.";
|
||||
|
||||
/* Explanation of what is done to keep private data encrypted. There is a heading that precedes this explanation which is a variable to this string. */
|
||||
"%@. End-to-End encrypted private messaging. Keep Big Tech out of your DMs" = "%@. Mensajes privados con cifrado de un extremo a otro. Mantén a los gigantes tecnológicos fuera de tus mensajes directos.";
|
||||
|
||||
/* Explanation of what can be done by users to earn money. There is a heading that precedes this explanation which is a variable to this string. */
|
||||
"%@. Tip your friend's posts and stack sats with Bitcoin⚡️, the native currency of the internet." = "%@. Deja propinas en las publicaciones de tus amigos y acumula sats con Bitcoin⚡️, la moneda nativa de internet.";
|
||||
|
||||
/* Number of reposts.
|
||||
Number of profiles a user is following. */
|
||||
"%lld" = "%lld";
|
||||
|
||||
/* Fraction of how many of the user's relay servers that are operational. */
|
||||
"%lld/%lld" = "%lld/%lld";
|
||||
|
||||
/* Placeholder for event mention. */
|
||||
"< e >" = "< e >";
|
||||
|
||||
/* Label to prompt for about text entry for user to describe about themself. */
|
||||
"About" = "Información";
|
||||
|
||||
/* Label for About Me section of user profile form. */
|
||||
"About Me" = "Acerca de mí";
|
||||
|
||||
/* Placeholder text for About Me description. */
|
||||
"Absolute Boss" = "Jefe supremo";
|
||||
|
||||
/* Label to indicate the public ID of the account. */
|
||||
"Account ID" = "Identificador de cuenta";
|
||||
|
||||
/* Button to add recommended relay server.
|
||||
Button to confirm adding user inputted relay. */
|
||||
"Add" = "Agregar";
|
||||
|
||||
/* Label for section for adding a relay server. */
|
||||
"Add Relay" = "Agregar relé";
|
||||
|
||||
/* Any amount of sats */
|
||||
"Any" = "Cualquiera";
|
||||
|
||||
/* Alert message to ask if user wants to repost a post. */
|
||||
"Are you sure you want to repost this?" = "¿Seguro quieres volver a publicar esto?";
|
||||
|
||||
/* Label for Banner Image section of user profile form. */
|
||||
"Banner Image" = "Imagen del banner";
|
||||
|
||||
/* Reminder to user that they should save their account information. */
|
||||
"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." = "Antes de empezar, tendrás que guardar la información de tu cuenta. De lo contrario, no podrás iniciar sesión en el futuro si llegas a desinstalar Damus.";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Bitcoin Beach. */
|
||||
"Bitcoin Beach" = "Bitcoin Beach";
|
||||
|
||||
/* Label for Bitcoin Lightning Tips section of user profile form. */
|
||||
"Bitcoin Lightning Tips" = "Propinas con Bitcoin Lightning";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Blixt Wallet */
|
||||
"Blixt Wallet" = "Blixt Wallet";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Blue Wallet. */
|
||||
"Blue Wallet" = "Blue Wallet";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Breez. */
|
||||
"Breez" = "Breez";
|
||||
|
||||
/* Context menu option for broadcasting the user's note to all of the user's connected relay servers. */
|
||||
"Broadcast" = "Transmitir";
|
||||
|
||||
/* 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. */
|
||||
"Cancel" = "Cancelar";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Cash App. */
|
||||
"Cash App" = "Cash App";
|
||||
|
||||
/* Navigation bar title for Chatroom view. */
|
||||
"Chat" = "Chat";
|
||||
|
||||
/* Button for clearing cached data. */
|
||||
"Clear" = "Borrar";
|
||||
|
||||
/* Section title for clearing cached data. */
|
||||
"Clear Cache" = "Borrar caché";
|
||||
|
||||
/* Label indicating that a user's key was copied. */
|
||||
"Copied" = "Copiada";
|
||||
|
||||
/* Button to copy a relay server address. */
|
||||
"Copy" = "Copiar";
|
||||
|
||||
/* Context menu option for copying the ID of the account that created the note. */
|
||||
"Copy Account ID" = "Copiar identificador de cuenta";
|
||||
|
||||
/* Context menu option to copy an image into clipboard.
|
||||
Context menu option to copy an image to clipboard. */
|
||||
"Copy Image" = "Copiar imagen";
|
||||
|
||||
/* Context menu option to copy the URL of an image into clipboard. */
|
||||
"Copy Image URL" = "Copiar URL de imagen";
|
||||
|
||||
/* Title of section for copying a Lightning invoice identifier. */
|
||||
"Copy invoice" = "Copiar factura";
|
||||
|
||||
/* Context menu option for copying a user's Lightning URL. */
|
||||
"Copy LNURL" = "Copiar LNURL";
|
||||
|
||||
/* Context menu option for copying the ID of the note. */
|
||||
"Copy Note ID" = "Copiar identificador de nota";
|
||||
|
||||
/* Context menu option for copying the JSON text from the note. */
|
||||
"Copy Note JSON" = "Copiar JSON de nota";
|
||||
|
||||
/* Context menu option for copying the text from an note. */
|
||||
"Copy Text" = "Copiar texto";
|
||||
|
||||
/* Context menu option for copying the ID of the user who created the note. */
|
||||
"Copy User ID" = "Copiar identificador de usuario";
|
||||
|
||||
/* Button to create account. */
|
||||
"Create" = "Crear";
|
||||
|
||||
/* Button to create an account. */
|
||||
"Create Account" = "Crear cuenta";
|
||||
|
||||
/* Example description about Bitcoin creator(s), Satoshi Nakamoto. */
|
||||
"Creator(s) of Bitcoin. Absolute legend." = "Creador(es) de Bitcoin. Toda una leyenda.";
|
||||
|
||||
/* Name of the app, shown on the first screen when user is not logged in. */
|
||||
"Damus" = "Damus";
|
||||
|
||||
/* Button to pay a Lightning invoice with the user's default Lightning wallet. */
|
||||
"Default Wallet" = "Billetera predeterminada";
|
||||
|
||||
/* Button to delete a relay server that the user connects to. */
|
||||
"Delete" = "Borrar";
|
||||
|
||||
/* Button to dismiss a text field alert. */
|
||||
"Dismiss" = "Descartar";
|
||||
|
||||
/* Label to prompt display name entry. */
|
||||
"Display Name" = "Mostrar nombre";
|
||||
|
||||
/* Navigation title for DM view, which is the English abbreviation for Direct Message. */
|
||||
"DM" = "MD";
|
||||
|
||||
/* Button to dismiss wallet selection view for paying Lightning invoice. */
|
||||
"Done" = "Listo";
|
||||
|
||||
/* Heading indicating that this application allows users to earn money. */
|
||||
"Earn Money" = "Gana dinero";
|
||||
|
||||
/* Button to edit user's profile. */
|
||||
"Edit" = "Editar";
|
||||
|
||||
/* Heading indicating that this application keeps private messaging end-to-end encrypted. */
|
||||
"Encrypted" = "Cifrada";
|
||||
|
||||
/* Navigation title for view of encrypted DMs, where DM is an English abbreviation for Direct Message. */
|
||||
"Encrypted DMs" = "MD cifrados";
|
||||
|
||||
/* Prompt for user to enter an account key to login. */
|
||||
"Enter your account key to login:" = "Ingresa la clave de tu cuenta para iniciar sesión:";
|
||||
|
||||
/* Error message indicating why saving keys failed. */
|
||||
"Error: %@" = "Error: %@";
|
||||
|
||||
/* Filter state for seeing either only posts, or posts & replies. */
|
||||
"Filter State" = "Estado del filtro";
|
||||
|
||||
/* Button to follow a user. */
|
||||
"Follow" = "Seguir";
|
||||
|
||||
/* Label describing followers of a user. */
|
||||
"Followers" = "Seguidores";
|
||||
|
||||
/* Text to indicate that the button next to it is in a state that indicates that it is in the process of following a profile.
|
||||
Part of a larger sentence to describe how many profiles a user is following. */
|
||||
"Following" = "Siguiendo";
|
||||
|
||||
/* Label to indicate that the user is in the process of following another user. */
|
||||
"Following..." = "Siguiendo...";
|
||||
|
||||
/* Text to indicate that button next to it is in a state that will follow a profile when tapped. */
|
||||
"Follows" = "Sigue";
|
||||
|
||||
/* Navigation bar title for Global view where posts from all connected relay servers appear. */
|
||||
"Global" = "Global";
|
||||
|
||||
/* Navigation link to go to post referenced by hex code. */
|
||||
"Goto post %@" = "Ir a la publicación %@";
|
||||
|
||||
/* Navigation link to go to profile. */
|
||||
"Goto profile %@" = "Ir al perfil %@";
|
||||
|
||||
/* Navigation bar title for Home view where posts and replies appear from those who the user is following. */
|
||||
"Home" = "Inicio";
|
||||
|
||||
/* Placeholder example text for profile picture URL. */
|
||||
"https://example.com/pic.jpg" = "https://ejemplo.com/foto.jpg";
|
||||
|
||||
/* Placeholder example text for website URL for user profile. */
|
||||
"https://jb55.com" = "https://jb55.com";
|
||||
|
||||
/* Error message indicating that an invalid account key was entered for login. */
|
||||
"Invalid key" = "Clave inválida";
|
||||
|
||||
/* Placeholder example text for identifier used for NIP-05 verification. */
|
||||
"jb55@jb55.com" = "jb55@jb55.com";
|
||||
|
||||
/* Moves the post button to the left side of the screen */
|
||||
"Left Handed" = "Zurdo";
|
||||
|
||||
/* Button to complete account creation and start using the app. */
|
||||
"Let's go!" = "¡Vamos!";
|
||||
|
||||
/* Placeholder text for entry of Lightning Address or LNURL. */
|
||||
"Lightning Address or LNURL" = "Dirección de Lightning o LNURL";
|
||||
|
||||
/* Indicates that the view is for paying a Lightning invoice. */
|
||||
"Lightning Invoice" = "Factura de Lightning";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, LNLink. */
|
||||
"LNLink" = "LNLink";
|
||||
|
||||
/* Dropdown option label for system default for Lightning wallet. */
|
||||
"Local default" = "Predeterminada del sistema";
|
||||
|
||||
/* Button to log into account.
|
||||
Button to log into an account. */
|
||||
"Login" = "Iniciar sesión";
|
||||
|
||||
/* Alert for logging out the user.
|
||||
Button for logging out the user.
|
||||
Button to logout the user. */
|
||||
"Logout" = "Cerrar sesión";
|
||||
|
||||
/* Reminder message in alert to get customer to verify that their private security account key is saved saved before logging out. */
|
||||
"Make sure your nsec account key is saved before you logout or you will lose access to this account" = "Asegúrate de que tu clave de cuenta nsec esté guardada antes de cerrar sesión o perderás el acceso a esta cuenta";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Muun. */
|
||||
"Muun" = "Muun";
|
||||
|
||||
/* Label for NIP-05 Verification section of user profile form. */
|
||||
"NIP-05 Verification" = "Verificación NIP-05";
|
||||
|
||||
/* No search results. */
|
||||
"none" = "ninguno";
|
||||
|
||||
/* Indicates that there are no notes in the timeline to view. */
|
||||
"Nothing to see here. Check back later!" = "Nada para ver aquí. ¡Vuelve a consultar luego!";
|
||||
|
||||
/* Navigation title for notifications. */
|
||||
"Notifications" = "Notificaciones";
|
||||
|
||||
/* String indicating that a given timestamp just occurred */
|
||||
"now" = "ahora";
|
||||
|
||||
/* Prompt for user to enter in an account key to login. This text shows the characters the key could start with if it was a private key. */
|
||||
"nsec1..." = "nsec1...";
|
||||
|
||||
/* Label indicating that a form input is optional. */
|
||||
"optional" = "opcional";
|
||||
|
||||
/* Button to pay a Lightning invoice. */
|
||||
"Pay" = "Pagar";
|
||||
|
||||
/* Navigation bar title for view to pay Lightning invoice. */
|
||||
"Pay the Lightning invoice" = "Paga la factura de Lightning";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Phoenix. */
|
||||
"Phoenix" = "Phoenix";
|
||||
|
||||
/* Button to post a note. */
|
||||
"Post" = "Publicar";
|
||||
|
||||
/* Label for filter for seeing only posts (instead of posts and replies). */
|
||||
"Posts" = "Publicaciones";
|
||||
|
||||
/* Label for filter for seeing posts and replies (instead of only posts). */
|
||||
"Posts & Replies" = "Publicaciones y respuestas";
|
||||
|
||||
/* Heading indicating that this application keeps personally identifiable information private. A sentence describing what is done to keep data private comes after this heading. */
|
||||
"Private" = "Privada";
|
||||
|
||||
/* Label to indicate that the text below is the user's private key used by only the user themself as a secret to login to access their account. */
|
||||
"Private Key" = "Clave privada";
|
||||
|
||||
/* Title of the secure field that holds the user's private key. */
|
||||
"PrivateKey" = "ClavePrivada";
|
||||
|
||||
/* Sidebar menu label for Profile view. */
|
||||
"Profile" = "Perfil";
|
||||
|
||||
/* Label for Profile Picture section of user profile form. */
|
||||
"Profile Picture" = "Foto del perfil";
|
||||
|
||||
/* Section title for the user's public account ID. */
|
||||
"Public Account ID" = "Identificador de cuenta pública";
|
||||
|
||||
/* Label indicating that the text is a user's public account key. */
|
||||
"Public key" = "Clave pública";
|
||||
|
||||
/* Label indicating that the text is a user's public account key. */
|
||||
"Public Key" = "Clave pública";
|
||||
|
||||
/* Prompt to ask user if the key they entered is a public key. */
|
||||
"Public Key?" = "¿Clave pública?";
|
||||
|
||||
/* Navigation bar title for Reactions view. */
|
||||
"Reactions" = "Reacciones";
|
||||
|
||||
/* Section title for recommend relay servers that could be added as part of configuration */
|
||||
"Recommended Relays" = "Relés recomendados";
|
||||
|
||||
/* Text field for relay server. Used for testing purposes. */
|
||||
"Relay" = "Relé";
|
||||
|
||||
/* Sidebar menu label for Relay servers view */
|
||||
"Relays" = "Relés";
|
||||
|
||||
/* Label to indicate that the user is replying to themself. */
|
||||
"Reply to self" = "Respuesta a sí mismo";
|
||||
|
||||
/* Label to indicate that the user is replying to 2 users. */
|
||||
"Replying to %@ & %@" = "Respondiendo a %1$@ y %2$@";
|
||||
|
||||
/* Indicating that the user is replying to the following listed people. */
|
||||
"Replying to:" = "Respondiendo a:";
|
||||
|
||||
/* Button to confirm reposting a post.
|
||||
Title of alert for confirming to repost a post. */
|
||||
"Repost" = "Republicar";
|
||||
|
||||
/* Text indicating that the post was reposted (i.e. re-shared). */
|
||||
"Reposted" = "Republicada";
|
||||
|
||||
/* Section title for resetting the user */
|
||||
"Reset" = "Reiniciar";
|
||||
|
||||
/* Button to retry completing account creation after an error occurred. */
|
||||
"Retry" = "Reintentar";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, River */
|
||||
"River" = "River";
|
||||
|
||||
/* Example username of Bitcoin creator(s), Satoshi Nakamoto. */
|
||||
"satoshi" = "satoshi";
|
||||
|
||||
/* Name of Bitcoin creator(s). */
|
||||
"Satoshi Nakamoto" = "Satoshi Nakamoto";
|
||||
|
||||
/* Button for saving profile. */
|
||||
"Save" = "Guardar";
|
||||
|
||||
/* Context menu option to save an image. */
|
||||
"Save Image" = "Guardar imagen";
|
||||
|
||||
/* Navigation link to search hashtag. */
|
||||
"Search hashtag: #%@" = "Buscar hashtag: #%@";
|
||||
|
||||
/* Placeholder text to prompt entry of search query. */
|
||||
"Search..." = "Búsqueda...";
|
||||
|
||||
/* Section title for user's secret account login key. */
|
||||
"Secret Account Login Key" = "Clave de inicio de sesión de cuenta secreta";
|
||||
|
||||
/* Title of section for selecting a Lightning wallet to pay a Lightning invoice. */
|
||||
"Select a Lightning wallet" = "Seleccionar una billetera de Lightning";
|
||||
|
||||
/* Prompt selection of user's default wallet */
|
||||
"Select default wallet" = "Seleccionar billetera predeterminada";
|
||||
|
||||
/* Text prompt for user to send a message to the other user. */
|
||||
"Send a message to start the conversation..." = "Envía un mensaje para empezar la conversación...";
|
||||
|
||||
/* Navigation title for Settings view.
|
||||
Sidebar menu label for accessing the app settings */
|
||||
"Settings" = "Configuración";
|
||||
|
||||
/* Button to share an image. */
|
||||
"Share" = "Compartir";
|
||||
|
||||
/* Toggle to show or hide user's secret account login key. */
|
||||
"Show" = "Mostrar";
|
||||
|
||||
/* Toggle to show or hide selection of wallet. */
|
||||
"Show wallet selector" = "Mostrar selector de billetera";
|
||||
|
||||
/* Sidebar menu label to sign out of the account. */
|
||||
"Sign out" = "Cerrar sesión";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Strike. */
|
||||
"Strike" = "Strike";
|
||||
|
||||
/* Warning that the inputted account key is a public key and the result of what happens because of it. */
|
||||
"This is a public key, you will not be able to make posts or interact in any way. This is used for viewing accounts from their perspective." = "Esta es una clave pública, por lo que no podrás hacer publicaciones ni interactuar de ningún modo. Se usa para ver cuentas desde su perspectiva.";
|
||||
|
||||
/* Warning that the inputted account key for login is an old-style and asking user to verify if it is a public key. */
|
||||
"This is an old-style nostr key. We're not sure if it's a pubkey or private key. Please toggle the button below if this a public key." = "Esta es una clave de nostr antigua. No sabemos con seguridad si es una clave pública o privada. Activa el siguiente botón si es una clave pública.";
|
||||
|
||||
/* Label to describe that a public key is the user's account ID and what they can do with it. */
|
||||
"This is your account ID, you can give this to your friends so that they can follow you. Click to copy." = "Este es tu identificador de cuenta, que puedes compartir con tus amigos para que te sigan. Haz clic para copiarlo.";
|
||||
|
||||
/* Label to describe that a private key is the user's secret account key and what they should do with it. */
|
||||
"This is your secret account key. You need this to access your account. Don't share this with anyone! Save it in a password manager and keep it safe!" = "Esta es tu clave de cuenta secreta, que necesitas para acceder a tu cuenta. ¡No la compartas con nadie! Guárdala en un administrador de contraseñas y protégela!";
|
||||
|
||||
/* Navigation bar title for note thread.
|
||||
Navigation bar title for threaded event detail view. */
|
||||
"Thread" = "Hilo";
|
||||
|
||||
/* Text box prompt to ask user to type their post. */
|
||||
"Type your post here..." = "Ingresa tu publicación aquí...";
|
||||
|
||||
/* Non-breaking space character to fill in blank space next to event action button icons. */
|
||||
"u{00A0}" = "u{00A0}";
|
||||
|
||||
/* Button to unfollow a user. */
|
||||
"Unfollow" = "Dejar de seguir";
|
||||
|
||||
/* Text to indicate that the button next to it is in a state that indicates that it is in the process of unfollowing a profile. */
|
||||
"Unfollowing" = "Dejando de seguir";
|
||||
|
||||
/* Label to indicate that the user is in the process of unfollowing another user. */
|
||||
"Unfollowing..." = "Dejando de seguir...";
|
||||
|
||||
/* Text to indicate that the button next to it is in a state that will unfollow a profile when tapped. */
|
||||
"Unfollows" = "Deja de seguir";
|
||||
|
||||
/* Label for Username section of user profile form.
|
||||
Label to prompt username entry. */
|
||||
"Username" = "Nombre de usuario";
|
||||
|
||||
/* Sidebar menu label for Wallet view. */
|
||||
"Wallet" = "Billetera";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Wallet Of Satoshi. */
|
||||
"Wallet Of Satoshi" = "Wallet Of Satoshi";
|
||||
|
||||
/* Section title for selection of wallet. */
|
||||
"Wallet Selector" = "Selección de billetera";
|
||||
|
||||
/* Label for Website section of user profile form. */
|
||||
"Website" = "Sitio web";
|
||||
|
||||
/* Welcoming message to the reader. The variable is 'you', the reader. */
|
||||
"Welcome to the social network %@ control." = "Te damos la bienvenida a la red social que %@ controlas.";
|
||||
|
||||
/* Text to welcome user. */
|
||||
"Welcome, %@!" = "¡Te damos la bienvenida, %@!";
|
||||
|
||||
/* Placeholder example for relay server address. */
|
||||
"wss://some.relay.com" = "wss://algún.relé.com";
|
||||
|
||||
/* 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. */
|
||||
"you" = "tú";
|
||||
|
||||
/* Label for Your Name section of user profile form. */
|
||||
"Your Name" = "Tu nombre";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Zebedee. */
|
||||
"Zebedee" = "Zebedee";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Zeus LN. */
|
||||
"Zeus LN" = "Zeus LN";
|
||||
|
||||
@@ -2,58 +2,152 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>replying_to_one_and_others</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>Replying to %@%#@OTHERS@</string>
|
||||
<key>OTHERS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>zero</key>
|
||||
<string></string>
|
||||
<key>one</key>
|
||||
<string> & 1 other</string>
|
||||
<key>other</key>
|
||||
<string> & %d others</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>replying_to_two_and_others</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>Replying to %@, %@%#@OTHERS@</string>
|
||||
<key>OTHERS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>zero</key>
|
||||
<string></string>
|
||||
<key>one</key>
|
||||
<string> & 1 other</string>
|
||||
<key>other</key>
|
||||
<string> & %d others</string>
|
||||
</dict>
|
||||
</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>zero</key>
|
||||
<string>0 notes</string>
|
||||
<key>one</key>
|
||||
<string>1 note</string>
|
||||
<string>%d otra nota</string>
|
||||
<key>other</key>
|
||||
<string>%d notes</string>
|
||||
<string>%d otras notas</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>··· %#@NOTES@ ···</string>
|
||||
</dict>
|
||||
<key>followers_count</key>
|
||||
<dict>
|
||||
<key>FOLLOWERS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Seguidor</string>
|
||||
<key>other</key>
|
||||
<string>Seguidores</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@FOLLOWERS@</string>
|
||||
</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>Reacción</string>
|
||||
<key>other</key>
|
||||
<string>Reacciones</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>Relé</string>
|
||||
<key>other</key>
|
||||
<string>Relés</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>replying_to_one_and_others</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>Respondiendo a %@%#@OTHERS@</string>
|
||||
<key>OTHERS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string> y %d otro</string>
|
||||
<key>other</key>
|
||||
<string> y %d otros</string>
|
||||
<key>zero</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>replying_to_two_and_others</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>Respondiendo a %@, %@%#@OTHERS@</string>
|
||||
<key>OTHERS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string> y %d otro</string>
|
||||
<key>other</key>
|
||||
<string> y %d otros</string>
|
||||
<key>zero</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>reposts_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@REPOSTS@</string>
|
||||
<key>REPOSTS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Republicación</string>
|
||||
<key>other</key>
|
||||
<string>Republicaciones</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>Propina</string>
|
||||
<key>other</key>
|
||||
<string>Propinas</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
|
||||
9
damus/fr-FR.lproj/InfoPlist.strings
Normal file
9
damus/fr-FR.lproj/InfoPlist.strings
Normal file
@@ -0,0 +1,9 @@
|
||||
/* Bundle display name */
|
||||
"CFBundleDisplayName" = "Damus";
|
||||
|
||||
/* Bundle name */
|
||||
"CFBundleName" = "damus";
|
||||
|
||||
/* Privacy - Photo Library Additions Usage Description */
|
||||
"NSPhotoLibraryAddUsageDescription" = "\"Accorder à Damus l'accès à votre galerie photos vous permet d'enregistrer des photos.";
|
||||
|
||||
493
damus/fr-FR.lproj/Localizable.strings
Normal file
493
damus/fr-FR.lproj/Localizable.strings
Normal file
@@ -0,0 +1,493 @@
|
||||
/* Blank space to separate profile picture from profile editor form. */
|
||||
" " = "61b6edf1108e6f396680a33b02486a70_tr";
|
||||
|
||||
/* Description of how the nip05 identifier would be used for verification. */
|
||||
"'%@' at '%@' will be used for verification" = "'%@' à '@' sera utilisé pour la vérification";
|
||||
|
||||
/* Description of why the nip05 identifier is invalid. */
|
||||
"'%@' is an invalid nip05 identifier. It should look like an email." = "'@' est un identifiant nip05 invalide. Cela devrait ressembler à une adresse e-mail.";
|
||||
|
||||
/* Navigation bar title for view that shows who is following a user. */
|
||||
"(Profile.displayName(profile: profile, pubkey: whos))'s Followers" = "(Profile.displayName(profile: profile, pubkey: whos))'s Followers";
|
||||
|
||||
/* Navigation bar title for view that shows who a user is following. */
|
||||
"(who) following" = "(who) following";
|
||||
|
||||
/* Prefix character to username. */
|
||||
"@" = "@";
|
||||
|
||||
/* Amount of time that has passed since reply quote event occurred.
|
||||
Abbreviated version of a nostr public key. */
|
||||
"%@" = "%@";
|
||||
|
||||
/* 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'. */
|
||||
"%@ %@" = "%@ %@";
|
||||
|
||||
/* Explanation of what is done to keep personally identifiable information private. There is a heading that precedes this explanation which is a variable to this string. */
|
||||
"%@. Creating an account doesn't require a phone number, email or name. Get started right away with zero friction." = "%@. La création d'un compte ne nécessite pas de numéro de téléphone, d'e-mail ou de nom. Commencez tout de suite sans aucune friction.";
|
||||
|
||||
/* Explanation of what is done to keep private data encrypted. There is a heading that precedes this explanation which is a variable to this string. */
|
||||
"%@. End-to-End encrypted private messaging. Keep Big Tech out of your DMs" = "%@. Messagerie privée cryptée de bout en bout. Gardez Big Tech hors de vos DMs";
|
||||
|
||||
/* Explanation of what can be done by users to earn money. There is a heading that precedes this explanation which is a variable to this string. */
|
||||
"%@. Tip your friend's posts and stack sats with Bitcoin⚡️, the native currency of the internet." = "%@. Donnez un pourboire aux publications de vos amis et empilez les sats avec Bitcoin⚡️, la monnaie native d'Internet.";
|
||||
|
||||
/* Number of reposts.
|
||||
Number of profiles a user is following. */
|
||||
"%lld" = "%lld";
|
||||
|
||||
/* Fraction of how many of the user's relay servers that are operational. */
|
||||
"%lld/%lld" = "%lld/%lld<br data-mce-bogus=\"1\">";
|
||||
|
||||
/* Placeholder for event mention. */
|
||||
"< e >" = "< e >";
|
||||
|
||||
/* Label to prompt for about text entry for user to describe about themself. */
|
||||
"About" = "À propos de";
|
||||
|
||||
/* Label for About Me section of user profile form. */
|
||||
"About Me" = "À Propos de Moi";
|
||||
|
||||
/* Placeholder text for About Me description. */
|
||||
"Absolute Boss" = "Patron Absolu";
|
||||
|
||||
/* Label to indicate the public ID of the account. */
|
||||
"Account ID" = "Identifiant de Compte";
|
||||
|
||||
/* Button to add recommended relay server.
|
||||
Button to confirm adding user inputted relay. */
|
||||
"Add" = "Ajouter";
|
||||
|
||||
/* Label for section for adding a relay server. */
|
||||
"Add Relay" = "Ajouter un Relais";
|
||||
|
||||
/* Any amount of sats */
|
||||
"Any" = "N'importe Lequel";
|
||||
|
||||
/* Alert message to ask if user wants to repost a post. */
|
||||
"Are you sure you want to repost this?" = "Êtes-vous sûr de vouloir republier ceci ?";
|
||||
|
||||
/* Label for Banner Image section of user profile form. */
|
||||
"Banner Image" = "Image Bannière";
|
||||
|
||||
/* Reminder to user that they should save their account information. */
|
||||
"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." = "Avant de commencer, vous devrez enregistrer les informations de votre compte, sinon vous ne pourrez plus vous connecter à l'avenir si vous désinstallez Damus.";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Bitcoin Beach. */
|
||||
"Bitcoin Beach" = "Bitcoin Beach";
|
||||
|
||||
/* Label for Bitcoin Lightning Tips section of user profile form. */
|
||||
"Bitcoin Lightning Tips" = "Pourboires de Bitcoin Lightning";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Blixt Wallet */
|
||||
"Blixt Wallet" = "Portefeuille Blixt";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Blue Wallet. */
|
||||
"Blue Wallet" = "Portefeuille Blue";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Breez. */
|
||||
"Breez" = "Breez";
|
||||
|
||||
/* Context menu option for broadcasting the user's note to all of the user's connected relay servers. */
|
||||
"Broadcast" = "Diffuser";
|
||||
|
||||
/* 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. */
|
||||
"Cancel" = "Annuler";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Cash App. */
|
||||
"Cash App" = "Cash App";
|
||||
|
||||
/* Navigation bar title for Chatroom view. */
|
||||
"Chat" = "Chatter";
|
||||
|
||||
/* Button for clearing cached data. */
|
||||
"Clear" = "<br>Vider";
|
||||
|
||||
/* Section title for clearing cached data. */
|
||||
"Clear Cache" = "Vider le Cache";
|
||||
|
||||
/* Label indicating that a user's key was copied. */
|
||||
"Copied" = "Copié";
|
||||
|
||||
/* Button to copy a relay server address. */
|
||||
"Copy" = "Copier";
|
||||
|
||||
/* Context menu option for copying the ID of the account that created the note. */
|
||||
"Copy Account ID" = "Copier l'Identifiant de Compte";
|
||||
|
||||
/* Context menu option to copy an image into clipboard.
|
||||
Context menu option to copy an image to clipboard. */
|
||||
"Copy Image" = "Copier l'Image";
|
||||
|
||||
/* Context menu option to copy the URL of an image into clipboard. */
|
||||
"Copy Image URL" = "Copier l'URL de l'Image";
|
||||
|
||||
/* Title of section for copying a Lightning invoice identifier. */
|
||||
"Copy invoice" = "Copier la Facture";
|
||||
|
||||
/* Context menu option for copying a user's Lightning URL. */
|
||||
"Copy LNURL" = "Copier le LNURL";
|
||||
|
||||
/* Context menu option for copying the ID of the note. */
|
||||
"Copy Note ID" = "Copier l'Identifiant de la Note";
|
||||
|
||||
/* Context menu option for copying the JSON text from the note. */
|
||||
"Copy Note JSON" = "Copier le JSON de la Note";
|
||||
|
||||
/* Context menu option for copying the text from an note. */
|
||||
"Copy Text" = "Copier le Texte";
|
||||
|
||||
/* Context menu option for copying the ID of the user who created the note. */
|
||||
"Copy User ID" = "Copier l'Identifiant de l'Utilisateur";
|
||||
|
||||
/* Button to create account. */
|
||||
"Create" = "Créer";
|
||||
|
||||
/* Button to create an account. */
|
||||
"Create Account" = "Créer un Compte";
|
||||
|
||||
/* Example description about Bitcoin creator(s), Satoshi Nakamoto. */
|
||||
"Creator(s) of Bitcoin. Absolute legend." = "Créateur(s) de Bitcoin. Légende absolue.";
|
||||
|
||||
/* Name of the app, shown on the first screen when user is not logged in. */
|
||||
"Damus" = "Damus";
|
||||
|
||||
/* Button to pay a Lightning invoice with the user's default Lightning wallet. */
|
||||
"Default Wallet" = "Portefeuille par défaut";
|
||||
|
||||
/* Button to delete a relay server that the user connects to. */
|
||||
"Delete" = "<br>Effacer";
|
||||
|
||||
/* Button to dismiss a text field alert. */
|
||||
"Dismiss" = "Rejeter";
|
||||
|
||||
/* Label to prompt display name entry. */
|
||||
"Display Name" = "Afficher Nom";
|
||||
|
||||
/* Navigation title for DM view, which is the English abbreviation for Direct Message. */
|
||||
"DM" = "DM";
|
||||
|
||||
/* Button to dismiss wallet selection view for paying Lightning invoice. */
|
||||
"Done" = "Fini";
|
||||
|
||||
/* Heading indicating that this application allows users to earn money. */
|
||||
"Earn Money" = "Gagnes de l'argent";
|
||||
|
||||
/* Button to edit user's profile. */
|
||||
"Edit" = "Modifier";
|
||||
|
||||
/* Heading indicating that this application keeps private messaging end-to-end encrypted. */
|
||||
"Encrypted" = "Crypté";
|
||||
|
||||
/* Navigation title for view of encrypted DMs, where DM is an English abbreviation for Direct Message. */
|
||||
"Encrypted DMs" = "DMs cryptés";
|
||||
|
||||
/* Prompt for user to enter an account key to login. */
|
||||
"Enter your account key to login:" = "Entrez votre clé de compte pour vous connecter:";
|
||||
|
||||
/* Error message indicating why saving keys failed. */
|
||||
"Error: %@" = "Error: %@";
|
||||
|
||||
/* Filter state for seeing either only posts, or posts & replies. */
|
||||
"Filter State" = "État du filtre";
|
||||
|
||||
/* Button to follow a user. */
|
||||
"Follow" = "S'abonner<br>";
|
||||
|
||||
/* Label describing followers of a user. */
|
||||
"Followers" = "Abonnés";
|
||||
|
||||
/* Text to indicate that the button next to it is in a state that indicates that it is in the process of following a profile.
|
||||
Part of a larger sentence to describe how many profiles a user is following. */
|
||||
"Following" = "Abonnements";
|
||||
|
||||
/* Label to indicate that the user is in the process of following another user. */
|
||||
"Following..." = "Abonnements...";
|
||||
|
||||
/* Text to indicate that button next to it is in a state that will follow a profile when tapped. */
|
||||
"Follows" = "Follow<br>";
|
||||
|
||||
/* Navigation bar title for Global view where posts from all connected relay servers appear. */
|
||||
"Global" = "Global";
|
||||
|
||||
/* Navigation link to go to post referenced by hex code. */
|
||||
"Goto post %@" = "Goto post %@";
|
||||
|
||||
/* Navigation link to go to profile. */
|
||||
"Goto profile %@" = "Goto profile %@";
|
||||
|
||||
/* Navigation bar title for Home view where posts and replies appear from those who the user is following. */
|
||||
"Home" = "Accueil";
|
||||
|
||||
/* Placeholder example text for profile picture URL. */
|
||||
"https://example.com/pic.jpg" = "https://example.com/pic.jpg";
|
||||
|
||||
/* Placeholder example text for website URL for user profile. */
|
||||
"https://jb55.com" = "https://jb55.com";
|
||||
|
||||
/* Error message indicating that an invalid account key was entered for login. */
|
||||
"Invalid key" = "Clé non valide";
|
||||
|
||||
/* Placeholder example text for identifier used for NIP-05 verification. */
|
||||
"jb55@jb55.com" = "jb55@jb55.com";
|
||||
|
||||
/* Moves the post button to the left side of the screen */
|
||||
"Left Handed" = "Gaucher";
|
||||
|
||||
/* Button to complete account creation and start using the app. */
|
||||
"Let's go!" = "Allons-y!";
|
||||
|
||||
/* Placeholder text for entry of Lightning Address or LNURL. */
|
||||
"Lightning Address or LNURL" = "Adresse Lightning ou LNURL";
|
||||
|
||||
/* Indicates that the view is for paying a Lightning invoice. */
|
||||
"Lightning Invoice" = "Facture Lightning";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, LNLink. */
|
||||
"LNLink" = "Lien LN";
|
||||
|
||||
/* Dropdown option label for system default for Lightning wallet. */
|
||||
"Local default" = "Valeur locale par défaut";
|
||||
|
||||
/* Button to log into account.
|
||||
Button to log into an account. */
|
||||
"Login" = "Se connecter";
|
||||
|
||||
/* Alert for logging out the user.
|
||||
Button for logging out the user.
|
||||
Button to logout the user. */
|
||||
"Logout" = "Se déconnecter";
|
||||
|
||||
/* Reminder message in alert to get customer to verify that their private security account key is saved saved before logging out. */
|
||||
"Make sure your nsec account key is saved before you logout or you will lose access to this account" = "Assurez-vous que votre clé de compte nsec est enregistrée avant de vous déconnecter ou vous perdrez l'accès à ce compte";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Muun. */
|
||||
"Muun" = "Muun";
|
||||
|
||||
/* Label for NIP-05 Verification section of user profile form. */
|
||||
"NIP-05 Verification" = "Vérification NIP-05";
|
||||
|
||||
/* No search results. */
|
||||
"none" = "none";
|
||||
|
||||
/* Indicates that there are no notes in the timeline to view. */
|
||||
"Nothing to see here. Check back later!" = "Rien à voir ici. Revenez plus tard!";
|
||||
|
||||
/* Navigation title for notifications. */
|
||||
"Notifications" = "Notifications";
|
||||
|
||||
/* String indicating that a given timestamp just occurred */
|
||||
"now" = "now";
|
||||
|
||||
/* Prompt for user to enter in an account key to login. This text shows the characters the key could start with if it was a private key. */
|
||||
"nsec1..." = "nsec1...";
|
||||
|
||||
/* Label indicating that a form input is optional. */
|
||||
"optional" = "optional";
|
||||
|
||||
/* Button to pay a Lightning invoice. */
|
||||
"Pay" = "Payer";
|
||||
|
||||
/* Navigation bar title for view to pay Lightning invoice. */
|
||||
"Pay the Lightning invoice" = "Payer la facture Lightning";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Phoenix. */
|
||||
"Phoenix" = "Phoenix";
|
||||
|
||||
/* Button to post a note. */
|
||||
"Post" = "Publication";
|
||||
|
||||
/* Label for filter for seeing only posts (instead of posts and replies). */
|
||||
"Posts" = "Publications";
|
||||
|
||||
/* Label for filter for seeing posts and replies (instead of only posts). */
|
||||
"Posts & Replies" = "Publications & Réponses";
|
||||
|
||||
/* Heading indicating that this application keeps personally identifiable information private. A sentence describing what is done to keep data private comes after this heading. */
|
||||
"Private" = "Privé";
|
||||
|
||||
/* Label to indicate that the text below is the user's private key used by only the user themself as a secret to login to access their account. */
|
||||
"Private Key" = "Clé Privée";
|
||||
|
||||
/* Title of the secure field that holds the user's private key. */
|
||||
"PrivateKey" = "PrivateKey";
|
||||
|
||||
/* Sidebar menu label for Profile view. */
|
||||
"Profile" = "Profil";
|
||||
|
||||
/* Label for Profile Picture section of user profile form. */
|
||||
"Profile Picture" = "Image de profil";
|
||||
|
||||
/* Section title for the user's public account ID. */
|
||||
"Public Account ID" = "Identifiant publique de compte";
|
||||
|
||||
/* Label indicating that the text is a user's public account key. */
|
||||
"Public key" = "Clé Publique";
|
||||
|
||||
/* Label indicating that the text is a user's public account key. */
|
||||
"Public Key" = "Clé Publique";
|
||||
|
||||
/* Prompt to ask user if the key they entered is a public key. */
|
||||
"Public Key?" = "Clé Publique?";
|
||||
|
||||
/* Navigation bar title for Reactions view. */
|
||||
"Reactions" = "Réactions";
|
||||
|
||||
/* Section title for recommend relay servers that could be added as part of configuration */
|
||||
"Recommended Relays" = "Relais Recommandés";
|
||||
|
||||
/* Text field for relay server. Used for testing purposes. */
|
||||
"Relay" = "Relais";
|
||||
|
||||
/* Sidebar menu label for Relay servers view */
|
||||
"Relays" = "Relais";
|
||||
|
||||
/* Label to indicate that the user is replying to themself. */
|
||||
"Reply to self" = "Répondre à soi-même";
|
||||
|
||||
/* Label to indicate that the user is replying to 2 users. */
|
||||
"Replying to %@ & %@" = "Répondre à %1$@ & %2$@";
|
||||
|
||||
/* Indicating that the user is replying to the following listed people. */
|
||||
"Replying to:" = "Répondre à:";
|
||||
|
||||
/* Button to confirm reposting a post.
|
||||
Title of alert for confirming to repost a post. */
|
||||
"Repost" = "Republier";
|
||||
|
||||
/* Text indicating that the post was reposted (i.e. re-shared). */
|
||||
"Reposted" = "A republié";
|
||||
|
||||
/* Section title for resetting the user */
|
||||
"Reset" = "Réinitialiser";
|
||||
|
||||
/* Button to retry completing account creation after an error occurred. */
|
||||
"Retry" = "Retenter";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, River */
|
||||
"River" = "River";
|
||||
|
||||
/* Example username of Bitcoin creator(s), Satoshi Nakamoto. */
|
||||
"satoshi" = "satoshi";
|
||||
|
||||
/* Name of Bitcoin creator(s). */
|
||||
"Satoshi Nakamoto" = "Satoshi Nakamoto";
|
||||
|
||||
/* Button for saving profile. */
|
||||
"Save" = "Enregistrer";
|
||||
|
||||
/* Context menu option to save an image. */
|
||||
"Save Image" = "Enregistrer Image";
|
||||
|
||||
/* Navigation link to search hashtag. */
|
||||
"Search hashtag: #%@" = "Rechercher hashtag: #%@";
|
||||
|
||||
/* Placeholder text to prompt entry of search query. */
|
||||
"Search..." = "Rechercher...";
|
||||
|
||||
/* Section title for user's secret account login key. */
|
||||
"Secret Account Login Key" = "Clé secrète de connexion au compte";
|
||||
|
||||
/* Title of section for selecting a Lightning wallet to pay a Lightning invoice. */
|
||||
"Select a Lightning wallet" = "Sélectionnez un portefeuille Lightning";
|
||||
|
||||
/* Prompt selection of user's default wallet */
|
||||
"Select default wallet" = "Sélectionnez le portefeuille par défaut";
|
||||
|
||||
/* Text prompt for user to send a message to the other user. */
|
||||
"Send a message to start the conversation..." = "Envoyez un message pour démarrer la conversation...";
|
||||
|
||||
/* Navigation title for Settings view.
|
||||
Sidebar menu label for accessing the app settings */
|
||||
"Settings" = "Paramètres";
|
||||
|
||||
/* Button to share an image. */
|
||||
"Share" = "Partager";
|
||||
|
||||
/* Toggle to show or hide user's secret account login key. */
|
||||
"Show" = "Afficher<br>";
|
||||
|
||||
/* Toggle to show or hide selection of wallet. */
|
||||
"Show wallet selector" = "Afficher le sélecteur de portefeuille";
|
||||
|
||||
/* Sidebar menu label to sign out of the account. */
|
||||
"Sign out" = "Se déconnecter";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Strike. */
|
||||
"Strike" = "Strike";
|
||||
|
||||
/* Warning that the inputted account key is a public key and the result of what happens because of it. */
|
||||
"This is a public key, you will not be able to make posts or interact in any way. This is used for viewing accounts from their perspective." = "Il s'agit d'une clé publique, vous ne pourrez pas publier de messages ou interagir de quelque manière que ce soit. Ceci est utilisé pour visualiser les comptes de leur point de vue.";
|
||||
|
||||
/* Warning that the inputted account key for login is an old-style and asking user to verify if it is a public key. */
|
||||
"This is an old-style nostr key. We're not sure if it's a pubkey or private key. Please toggle the button below if this a public key." = "Il s'agit d'une clé Nostr à l'ancienne. Nous ne savons pas s'il s'agit d'une clé publique ou d'une clé privée. Veuillez basculer le bouton ci-dessous s'il s'agit d'une clé publique.";
|
||||
|
||||
/* Label to describe that a public key is the user's account ID and what they can do with it. */
|
||||
"This is your account ID, you can give this to your friends so that they can follow you. Click to copy." = "Ceci est votre identifiant de compte, vous pouvez le donner à vos amis afin qu'ils puissent vous suivre. Cliquez pour copier.";
|
||||
|
||||
/* Label to describe that a private key is the user's secret account key and what they should do with it. */
|
||||
"This is your secret account key. You need this to access your account. Don't share this with anyone! Save it in a password manager and keep it safe!" = "Il s'agit de votre clé de compte secrète. Vous en aurez besoin pour accéder à votre compte. Ne le partagez avec personne ! Enregistrez-le dans un gestionnaire de mots de passe et gardez-le en sécurité!";
|
||||
|
||||
/* Navigation bar title for note thread.
|
||||
Navigation bar title for threaded event detail view. */
|
||||
"Thread" = "Fil de discussion";
|
||||
|
||||
/* Text box prompt to ask user to type their post. */
|
||||
"Type your post here..." = "Tapez votre message ici...";
|
||||
|
||||
/* Non-breaking space character to fill in blank space next to event action button icons. */
|
||||
"u{00A0}" = "u{00A0}";
|
||||
|
||||
/* Button to unfollow a user. */
|
||||
"Unfollow" = "Se désabonner";
|
||||
|
||||
/* Text to indicate that the button next to it is in a state that indicates that it is in the process of unfollowing a profile. */
|
||||
"Unfollowing" = "Ne plus suivre";
|
||||
|
||||
/* Label to indicate that the user is in the process of unfollowing another user. */
|
||||
"Unfollowing..." = "Ne plus suivre...<br>";
|
||||
|
||||
/* Text to indicate that the button next to it is in a state that will unfollow a profile when tapped. */
|
||||
"Unfollows" = "Se désabonne de";
|
||||
|
||||
/* Label for Username section of user profile form.
|
||||
Label to prompt username entry. */
|
||||
"Username" = "Nom d'utilisateur";
|
||||
|
||||
/* Sidebar menu label for Wallet view. */
|
||||
"Wallet" = "Portefeuille";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Wallet Of Satoshi. */
|
||||
"Wallet Of Satoshi" = "Portefeuille de Satoshi";
|
||||
|
||||
/* Section title for selection of wallet. */
|
||||
"Wallet Selector" = "Sélecteur de portefeuille";
|
||||
|
||||
/* Label for Website section of user profile form. */
|
||||
"Website" = "Site Internet";
|
||||
|
||||
/* Welcoming message to the reader. The variable is 'you', the reader. */
|
||||
"Welcome to the social network %@ control." = "Bienvenue sur le réseau social %@ contrôle.";
|
||||
|
||||
/* Text to welcome user. */
|
||||
"Welcome, %@!" = "Bienvenue, %@!";
|
||||
|
||||
/* Placeholder example for relay server address. */
|
||||
"wss://some.relay.com" = "wss://some.relay.com";
|
||||
|
||||
/* 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. */
|
||||
"you" = "you";
|
||||
|
||||
/* Label for Your Name section of user profile form. */
|
||||
"Your Name" = "Votre Nom";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Zebedee. */
|
||||
"Zebedee" = "Zebedee";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Zeus LN. */
|
||||
"Zeus LN" = "LN de Zeus";
|
||||
|
||||
154
damus/fr-FR.lproj/Localizable.stringsdict
Normal file
154
damus/fr-FR.lproj/Localizable.stringsdict
Normal file
@@ -0,0 +1,154 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>collapsed_event_view_other_notes</key>
|
||||
<dict>
|
||||
<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>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>··· %#@NOTES@ ···</string>
|
||||
</dict>
|
||||
<key>followers_count</key>
|
||||
<dict>
|
||||
<key>FOLLOWERS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Abonné</string>
|
||||
<key>other</key>
|
||||
<string>Abonnés</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@FOLLOWERS@</string>
|
||||
</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>Réaction</string>
|
||||
<key>other</key>
|
||||
<string>Réactions</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>Relais</string>
|
||||
<key>other</key>
|
||||
<string>Relais</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>replying_to_one_and_others</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>Répondre à %@%#@OTHERS@</string>
|
||||
<key>OTHERS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>& %d other</string>
|
||||
<key>other</key>
|
||||
<string>& %d others</string>
|
||||
<key>zero</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>replying_to_two_and_others</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>Répondre à %@, %@%#@OTHERS@</string>
|
||||
<key>OTHERS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>& %d other</string>
|
||||
<key>other</key>
|
||||
<string>& %d others</string>
|
||||
<key>zero</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>reposts_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@REPOSTS@</string>
|
||||
<key>REPOSTS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Republication</string>
|
||||
<key>other</key>
|
||||
<string>Republications</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>Pourboire</string>
|
||||
<key>other</key>
|
||||
<string>Pourboires</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
9
damus/tr-TR.lproj/InfoPlist.strings
Normal file
9
damus/tr-TR.lproj/InfoPlist.strings
Normal file
@@ -0,0 +1,9 @@
|
||||
/* Bundle display name */
|
||||
"CFBundleDisplayName" = "Damus";
|
||||
|
||||
/* Bundle name */
|
||||
"CFBundleName" = "damus";
|
||||
|
||||
/* Privacy - Photo Library Additions Usage Description */
|
||||
"NSPhotoLibraryAddUsageDescription" = "Damus'a fotoğraf kitaplığınıza erişim izni vermek, fotoğrafları kaydetmenize olanak tanır.";
|
||||
|
||||
493
damus/tr-TR.lproj/Localizable.strings
Normal file
493
damus/tr-TR.lproj/Localizable.strings
Normal file
@@ -0,0 +1,493 @@
|
||||
/* Blank space to separate profile picture from profile editor form. */
|
||||
" " = "61b6edf1108e6f396680a33b02486a70_tr";
|
||||
|
||||
/* Description of how the nip05 identifier would be used for verification. */
|
||||
"'%@' at '%@' will be used for verification" = "'%@' adresindeki '%@' doğrulama için kullanılacaktır";
|
||||
|
||||
/* Description of why the nip05 identifier is invalid. */
|
||||
"'%@' is an invalid nip05 identifier. It should look like an email." = "'%@' geçersiz bir nip05 tanımlayıcısı. Tanımlayıcı, e-posta gibi gözükmeli. ";
|
||||
|
||||
/* Navigation bar title for view that shows who is following a user. */
|
||||
"(Profile.displayName(profile: profile, pubkey: whos))'s Followers" = "(Profile.displayName(profile: profile, pubkey: whos))'nin Takipçileri";
|
||||
|
||||
/* Navigation bar title for view that shows who a user is following. */
|
||||
"(who) following" = "(who)'nin Takip Ettikleri";
|
||||
|
||||
/* Prefix character to username. */
|
||||
"@" = "@";
|
||||
|
||||
/* Amount of time that has passed since reply quote event occurred.
|
||||
Abbreviated version of a nostr public key. */
|
||||
"%@" = "%@";
|
||||
|
||||
/* 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'. */
|
||||
"%@ %@" = "%@ %@";
|
||||
|
||||
/* Explanation of what is done to keep personally identifiable information private. There is a heading that precedes this explanation which is a variable to this string. */
|
||||
"%@. Creating an account doesn't require a phone number, email or name. Get started right away with zero friction." = "%@. Hesap oluşturmak için telefon numarası, e-posta veya isim gerekmez. Vakit kaybetmeden hemen hemen başlayın.";
|
||||
|
||||
/* Explanation of what is done to keep private data encrypted. There is a heading that precedes this explanation which is a variable to this string. */
|
||||
"%@. End-to-End encrypted private messaging. Keep Big Tech out of your DMs" = "%@. Uçtan uca şifreli özel mesajlaşma. Teknoloji baronlarını DM'lerinden uzak tut";
|
||||
|
||||
/* Explanation of what can be done by users to earn money. There is a heading that precedes this explanation which is a variable to this string. */
|
||||
"%@. Tip your friend's posts and stack sats with Bitcoin⚡️, the native currency of the internet." = "%@. Arkadaşlarınızın gönderilerine bahşiş verin ve internetin yerel para birimi olan Bitcoin⚡️ ile sats biriktirin.";
|
||||
|
||||
/* Number of reposts.
|
||||
Number of profiles a user is following. */
|
||||
"%lld" = "%lld";
|
||||
|
||||
/* Fraction of how many of the user's relay servers that are operational. */
|
||||
"%lld/%lld" = "%lld/%lld";
|
||||
|
||||
/* Placeholder for event mention. */
|
||||
"< e >" = "< e >";
|
||||
|
||||
/* Label to prompt for about text entry for user to describe about themself. */
|
||||
"About" = "Hakkında";
|
||||
|
||||
/* Label for About Me section of user profile form. */
|
||||
"About Me" = "Hakkında";
|
||||
|
||||
/* Placeholder text for About Me description. */
|
||||
"Absolute Boss" = "Kral Adam";
|
||||
|
||||
/* Label to indicate the public ID of the account. */
|
||||
"Account ID" = "Hesap Kimliği";
|
||||
|
||||
/* Button to add recommended relay server.
|
||||
Button to confirm adding user inputted relay. */
|
||||
"Add" = "Ekle";
|
||||
|
||||
/* Label for section for adding a relay server. */
|
||||
"Add Relay" = "Röle Ekle";
|
||||
|
||||
/* Any amount of sats */
|
||||
"Any" = "Herhangi";
|
||||
|
||||
/* Alert message to ask if user wants to repost a post. */
|
||||
"Are you sure you want to repost this?" = "Bu gönderiyi yinelemek istediğinden emin misin?";
|
||||
|
||||
/* Label for Banner Image section of user profile form. */
|
||||
"Banner Image" = "Pankart Resmi";
|
||||
|
||||
/* Reminder to user that they should save their account information. */
|
||||
"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." = "Başlamadan önce, hesap bilgilierini kaydetmen gerekiyor. Aksi takdirde, Damus'u silme durumunda hesabına giriş yapamayacaksın.";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Bitcoin Beach. */
|
||||
"Bitcoin Beach" = "Bitcoin Beach";
|
||||
|
||||
/* Label for Bitcoin Lightning Tips section of user profile form. */
|
||||
"Bitcoin Lightning Tips" = "Bitcoin Lightning Bahşişleri";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Blixt Wallet */
|
||||
"Blixt Wallet" = "Blixt Wallet";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Blue Wallet. */
|
||||
"Blue Wallet" = "Blue Wallet";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Breez. */
|
||||
"Breez" = "Breez";
|
||||
|
||||
/* Context menu option for broadcasting the user's note to all of the user's connected relay servers. */
|
||||
"Broadcast" = "Yayınla";
|
||||
|
||||
/* 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. */
|
||||
"Cancel" = "İptal Et";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Cash App. */
|
||||
"Cash App" = "Cash App";
|
||||
|
||||
/* Navigation bar title for Chatroom view. */
|
||||
"Chat" = "Sohbet";
|
||||
|
||||
/* Button for clearing cached data. */
|
||||
"Clear" = "Temizle";
|
||||
|
||||
/* Section title for clearing cached data. */
|
||||
"Clear Cache" = "Önbelleği Temizle";
|
||||
|
||||
/* Label indicating that a user's key was copied. */
|
||||
"Copied" = "Kopyalandı";
|
||||
|
||||
/* Button to copy a relay server address. */
|
||||
"Copy" = "Kopyala";
|
||||
|
||||
/* Context menu option for copying the ID of the account that created the note. */
|
||||
"Copy Account ID" = "Hesap Kimliğini Kopyala";
|
||||
|
||||
/* Context menu option to copy an image into clipboard.
|
||||
Context menu option to copy an image to clipboard. */
|
||||
"Copy Image" = "Resmi Kopyala";
|
||||
|
||||
/* Context menu option to copy the URL of an image into clipboard. */
|
||||
"Copy Image URL" = "Resim URL'sini Kopyala";
|
||||
|
||||
/* Title of section for copying a Lightning invoice identifier. */
|
||||
"Copy invoice" = "Faturayı Kopyala";
|
||||
|
||||
/* Context menu option for copying a user's Lightning URL. */
|
||||
"Copy LNURL" = "LNURL'i Kopyala";
|
||||
|
||||
/* Context menu option for copying the ID of the note. */
|
||||
"Copy Note ID" = "Gönderi Kimliğini Kopyala ";
|
||||
|
||||
/* Context menu option for copying the JSON text from the note. */
|
||||
"Copy Note JSON" = "Gönderinin JSON Metnini Kopyala";
|
||||
|
||||
/* Context menu option for copying the text from an note. */
|
||||
"Copy Text" = "Metni Kopyala";
|
||||
|
||||
/* Context menu option for copying the ID of the user who created the note. */
|
||||
"Copy User ID" = "Hesap Kimliğini Kopyala";
|
||||
|
||||
/* Button to create account. */
|
||||
"Create" = "Yarat";
|
||||
|
||||
/* Button to create an account. */
|
||||
"Create Account" = "Hesap Yarat";
|
||||
|
||||
/* Example description about Bitcoin creator(s), Satoshi Nakamoto. */
|
||||
"Creator(s) of Bitcoin. Absolute legend." = "Bitcoin'in Yaratıcısı. Kral Adam.";
|
||||
|
||||
/* Name of the app, shown on the first screen when user is not logged in. */
|
||||
"Damus" = "Damus";
|
||||
|
||||
/* Button to pay a Lightning invoice with the user's default Lightning wallet. */
|
||||
"Default Wallet" = "Varsayılan Cüzdan";
|
||||
|
||||
/* Button to delete a relay server that the user connects to. */
|
||||
"Delete" = "Sil";
|
||||
|
||||
/* Button to dismiss a text field alert. */
|
||||
"Dismiss" = "Yok Say";
|
||||
|
||||
/* Label to prompt display name entry. */
|
||||
"Display Name" = "Görünür İsim";
|
||||
|
||||
/* Navigation title for DM view, which is the English abbreviation for Direct Message. */
|
||||
"DM" = "DM";
|
||||
|
||||
/* Button to dismiss wallet selection view for paying Lightning invoice. */
|
||||
"Done" = "Tamam";
|
||||
|
||||
/* Heading indicating that this application allows users to earn money. */
|
||||
"Earn Money" = "Para Kazan";
|
||||
|
||||
/* Button to edit user's profile. */
|
||||
"Edit" = "Düzenle";
|
||||
|
||||
/* Heading indicating that this application keeps private messaging end-to-end encrypted. */
|
||||
"Encrypted" = "Şifreli";
|
||||
|
||||
/* Navigation title for view of encrypted DMs, where DM is an English abbreviation for Direct Message. */
|
||||
"Encrypted DMs" = "Şifreli DM'ler";
|
||||
|
||||
/* Prompt for user to enter an account key to login. */
|
||||
"Enter your account key to login:" = "Giriş yapmak için hesap anahtarını gir:";
|
||||
|
||||
/* Error message indicating why saving keys failed. */
|
||||
"Error: %@" = "Hata: %@";
|
||||
|
||||
/* Filter state for seeing either only posts, or posts & replies. */
|
||||
"Filter State" = "Filtre Durumu";
|
||||
|
||||
/* Button to follow a user. */
|
||||
"Follow" = "Takip Et";
|
||||
|
||||
/* Label describing followers of a user. */
|
||||
"Followers" = "Takipçiler";
|
||||
|
||||
/* Text to indicate that the button next to it is in a state that indicates that it is in the process of following a profile.
|
||||
Part of a larger sentence to describe how many profiles a user is following. */
|
||||
"Following" = "Takip Ediliyor";
|
||||
|
||||
/* Label to indicate that the user is in the process of following another user. */
|
||||
"Following..." = "Takip Ediliyor...";
|
||||
|
||||
/* Text to indicate that button next to it is in a state that will follow a profile when tapped. */
|
||||
"Follows" = "Takipler";
|
||||
|
||||
/* Navigation bar title for Global view where posts from all connected relay servers appear. */
|
||||
"Global" = "Küresel";
|
||||
|
||||
/* Navigation link to go to post referenced by hex code. */
|
||||
"Goto post %@" = "%@'a git";
|
||||
|
||||
/* Navigation link to go to profile. */
|
||||
"Goto profile %@" = "%@'a git";
|
||||
|
||||
/* Navigation bar title for Home view where posts and replies appear from those who the user is following. */
|
||||
"Home" = "Ev";
|
||||
|
||||
/* Placeholder example text for profile picture URL. */
|
||||
"https://example.com/pic.jpg" = "https://example.com/pic.jpg";
|
||||
|
||||
/* Placeholder example text for website URL for user profile. */
|
||||
"https://jb55.com" = "https://jb55.com";
|
||||
|
||||
/* Error message indicating that an invalid account key was entered for login. */
|
||||
"Invalid key" = "Hatalı anahtar";
|
||||
|
||||
/* Placeholder example text for identifier used for NIP-05 verification. */
|
||||
"jb55@jb55.com" = "jb55@jb55.com";
|
||||
|
||||
/* Moves the post button to the left side of the screen */
|
||||
"Left Handed" = "Solak Modu";
|
||||
|
||||
/* Button to complete account creation and start using the app. */
|
||||
"Let's go!" = "Haydi Başla!";
|
||||
|
||||
/* Placeholder text for entry of Lightning Address or LNURL. */
|
||||
"Lightning Address or LNURL" = "Lightning Adresi ya da LNURL";
|
||||
|
||||
/* Indicates that the view is for paying a Lightning invoice. */
|
||||
"Lightning Invoice" = "Lightning Faturası";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, LNLink. */
|
||||
"LNLink" = "LNLink";
|
||||
|
||||
/* Dropdown option label for system default for Lightning wallet. */
|
||||
"Local default" = "Cihaz varsayılanı";
|
||||
|
||||
/* Button to log into account.
|
||||
Button to log into an account. */
|
||||
"Login" = "Giriş yap";
|
||||
|
||||
/* Alert for logging out the user.
|
||||
Button for logging out the user.
|
||||
Button to logout the user. */
|
||||
"Logout" = "Çıkış yap";
|
||||
|
||||
/* Reminder message in alert to get customer to verify that their private security account key is saved saved before logging out. */
|
||||
"Make sure your nsec account key is saved before you logout or you will lose access to this account" = "Çıkış yapmadan önce, nsec hesap anahtarını kaydetmeyi unutma. Aksi takdirde bu hesaba giremeyeceksin.";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Muun. */
|
||||
"Muun" = "Muun";
|
||||
|
||||
/* Label for NIP-05 Verification section of user profile form. */
|
||||
"NIP-05 Verification" = "NIP-05 Doğrulaması";
|
||||
|
||||
/* No search results. */
|
||||
"none" = "sonuç yok";
|
||||
|
||||
/* Indicates that there are no notes in the timeline to view. */
|
||||
"Nothing to see here. Check back later!" = "Görülecek bir şey yok. Daha sonra tekrar kontrol et!";
|
||||
|
||||
/* Navigation title for notifications. */
|
||||
"Notifications" = "Bildirimler";
|
||||
|
||||
/* String indicating that a given timestamp just occurred */
|
||||
"now" = "şimdi";
|
||||
|
||||
/* Prompt for user to enter in an account key to login. This text shows the characters the key could start with if it was a private key. */
|
||||
"nsec1..." = "nsec1...";
|
||||
|
||||
/* Label indicating that a form input is optional. */
|
||||
"optional" = "opsiyonel";
|
||||
|
||||
/* Button to pay a Lightning invoice. */
|
||||
"Pay" = "Öde";
|
||||
|
||||
/* Navigation bar title for view to pay Lightning invoice. */
|
||||
"Pay the Lightning invoice" = "Lightning faturasını öde";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Phoenix. */
|
||||
"Phoenix" = "Phoenix";
|
||||
|
||||
/* Button to post a note. */
|
||||
"Post" = "Gönder";
|
||||
|
||||
/* Label for filter for seeing only posts (instead of posts and replies). */
|
||||
"Posts" = "Gönderiler";
|
||||
|
||||
/* Label for filter for seeing posts and replies (instead of only posts). */
|
||||
"Posts & Replies" = "Gönderiler & Yorumlar";
|
||||
|
||||
/* Heading indicating that this application keeps personally identifiable information private. A sentence describing what is done to keep data private comes after this heading. */
|
||||
"Private" = "Özel";
|
||||
|
||||
/* Label to indicate that the text below is the user's private key used by only the user themself as a secret to login to access their account. */
|
||||
"Private Key" = "Özel Anahtar";
|
||||
|
||||
/* Title of the secure field that holds the user's private key. */
|
||||
"PrivateKey" = "Özel Anahtar";
|
||||
|
||||
/* Sidebar menu label for Profile view. */
|
||||
"Profile" = "Profil";
|
||||
|
||||
/* Label for Profile Picture section of user profile form. */
|
||||
"Profile Picture" = "Profil Fotoğrafı";
|
||||
|
||||
/* Section title for the user's public account ID. */
|
||||
"Public Account ID" = "Herkese Açık Hesap Kimliği";
|
||||
|
||||
/* Label indicating that the text is a user's public account key. */
|
||||
"Public key" = "Umumi anahtar";
|
||||
|
||||
/* Label indicating that the text is a user's public account key. */
|
||||
"Public Key" = "Herkese Açık Anahtar";
|
||||
|
||||
/* Prompt to ask user if the key they entered is a public key. */
|
||||
"Public Key?" = "Herkese Açık Anahtar?";
|
||||
|
||||
/* Navigation bar title for Reactions view. */
|
||||
"Reactions" = "Tepkiler";
|
||||
|
||||
/* Section title for recommend relay servers that could be added as part of configuration */
|
||||
"Recommended Relays" = "Önerilen Röleler";
|
||||
|
||||
/* Text field for relay server. Used for testing purposes. */
|
||||
"Relay" = "Röle";
|
||||
|
||||
/* Sidebar menu label for Relay servers view */
|
||||
"Relays" = "Röleler";
|
||||
|
||||
/* Label to indicate that the user is replying to themself. */
|
||||
"Reply to self" = "Kendine yanıt ver";
|
||||
|
||||
/* Label to indicate that the user is replying to 2 users. */
|
||||
"Replying to %@ & %@" = "%1$@ & %2$@'ya yanıt ver";
|
||||
|
||||
/* Indicating that the user is replying to the following listed people. */
|
||||
"Replying to:" = "Şunlara yanıt ver:";
|
||||
|
||||
/* Button to confirm reposting a post.
|
||||
Title of alert for confirming to repost a post. */
|
||||
"Repost" = "Yinele";
|
||||
|
||||
/* Text indicating that the post was reposted (i.e. re-shared). */
|
||||
"Reposted" = "Yinelendi";
|
||||
|
||||
/* Section title for resetting the user */
|
||||
"Reset" = "Sıfırla";
|
||||
|
||||
/* Button to retry completing account creation after an error occurred. */
|
||||
"Retry" = "Yeniden Dene";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, River */
|
||||
"River" = "River";
|
||||
|
||||
/* Example username of Bitcoin creator(s), Satoshi Nakamoto. */
|
||||
"satoshi" = "satoshi";
|
||||
|
||||
/* Name of Bitcoin creator(s). */
|
||||
"Satoshi Nakamoto" = "Satoshi Nakamoto";
|
||||
|
||||
/* Button for saving profile. */
|
||||
"Save" = "Kaydet";
|
||||
|
||||
/* Context menu option to save an image. */
|
||||
"Save Image" = "Resmi Kaydet";
|
||||
|
||||
/* Navigation link to search hashtag. */
|
||||
"Search hashtag: #%@" = "Etiketi ara: #%@";
|
||||
|
||||
/* Placeholder text to prompt entry of search query. */
|
||||
"Search..." = "Ara...";
|
||||
|
||||
/* Section title for user's secret account login key. */
|
||||
"Secret Account Login Key" = "Gizli Hesap Giriş Anahtarı";
|
||||
|
||||
/* Title of section for selecting a Lightning wallet to pay a Lightning invoice. */
|
||||
"Select a Lightning wallet" = "Bir Lightning cüzdanı seç";
|
||||
|
||||
/* Prompt selection of user's default wallet */
|
||||
"Select default wallet" = "Varsayılan cüzdanı seç";
|
||||
|
||||
/* Text prompt for user to send a message to the other user. */
|
||||
"Send a message to start the conversation..." = "Sohbeti başlatmak için bir mesaj gönder";
|
||||
|
||||
/* Navigation title for Settings view.
|
||||
Sidebar menu label for accessing the app settings */
|
||||
"Settings" = "Ayarlar";
|
||||
|
||||
/* Button to share an image. */
|
||||
"Share" = "Paylaş";
|
||||
|
||||
/* Toggle to show or hide user's secret account login key. */
|
||||
"Show" = "Göster";
|
||||
|
||||
/* Toggle to show or hide selection of wallet. */
|
||||
"Show wallet selector" = "Cüzdan seçiciyi göster";
|
||||
|
||||
/* Sidebar menu label to sign out of the account. */
|
||||
"Sign out" = "Çıkış yap";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Strike. */
|
||||
"Strike" = "Strike";
|
||||
|
||||
/* Warning that the inputted account key is a public key and the result of what happens because of it. */
|
||||
"This is a public key, you will not be able to make posts or interact in any way. This is used for viewing accounts from their perspective." = "Bu herkese açık bir anahtardır, herhangi bir şekilde gönderi yapamaz veya etkileşimde bulunamazsınız. Bu, hesapları kendi bakış açılarından görüntülemek için kullanılır.";
|
||||
|
||||
/* Warning that the inputted account key for login is an old-style and asking user to verify if it is a public key. */
|
||||
"This is an old-style nostr key. We're not sure if it's a pubkey or private key. Please toggle the button below if this a public key." = "Bu eski tip bir nostr anahtarı. Bunun bir pubkey mi yoksa private key mi olduğundan emin değiliz. Bu bir genel anahtarsa lütfen aşağıdaki düğmeyi değiştirin.";
|
||||
|
||||
/* Label to describe that a public key is the user's account ID and what they can do with it. */
|
||||
"This is your account ID, you can give this to your friends so that they can follow you. Click to copy." = "Bu sizin hesap kimliğinizdir, sizi takip edebilmeleri için bunu arkadaşlarınıza verebilirsiniz. Kopyalamak için tıklayın.";
|
||||
|
||||
/* Label to describe that a private key is the user's secret account key and what they should do with it. */
|
||||
"This is your secret account key. You need this to access your account. Don't share this with anyone! Save it in a password manager and keep it safe!" = "Bu sizin gizli hesap anahtarınızdır. Hesabınıza erişmek için buna ihtiyacınız var. Bunu kimseyle paylaşmayın! Bir şifre yöneticisine kaydedin ve güvende tutun!";
|
||||
|
||||
/* Navigation bar title for note thread.
|
||||
Navigation bar title for threaded event detail view. */
|
||||
"Thread" = "Konu";
|
||||
|
||||
/* Text box prompt to ask user to type their post. */
|
||||
"Type your post here..." = "Gönderinizi buraya yazın...";
|
||||
|
||||
/* Non-breaking space character to fill in blank space next to event action button icons. */
|
||||
"u{00A0}" = "u{00A0}";
|
||||
|
||||
/* Button to unfollow a user. */
|
||||
"Unfollow" = "Takipten Çık";
|
||||
|
||||
/* Text to indicate that the button next to it is in a state that indicates that it is in the process of unfollowing a profile. */
|
||||
"Unfollowing" = "Takipten Çıkılıyor";
|
||||
|
||||
/* Label to indicate that the user is in the process of unfollowing another user. */
|
||||
"Unfollowing..." = "Takipten Çıkılıyor...";
|
||||
|
||||
/* Text to indicate that the button next to it is in a state that will unfollow a profile when tapped. */
|
||||
"Unfollows" = "Takipten Çık";
|
||||
|
||||
/* Label for Username section of user profile form.
|
||||
Label to prompt username entry. */
|
||||
"Username" = "Kullanıcı Adı";
|
||||
|
||||
/* Sidebar menu label for Wallet view. */
|
||||
"Wallet" = "Cüzdan";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Wallet Of Satoshi. */
|
||||
"Wallet Of Satoshi" = "Wallet Of Satoshi";
|
||||
|
||||
/* Section title for selection of wallet. */
|
||||
"Wallet Selector" = "Cüzdan Seçici";
|
||||
|
||||
/* Label for Website section of user profile form. */
|
||||
"Website" = "Websitesi";
|
||||
|
||||
/* Welcoming message to the reader. The variable is 'you', the reader. */
|
||||
"Welcome to the social network %@ control." = "Kontrolün %@'da olduğu sosyal ağa hoş geldiniz.";
|
||||
|
||||
/* Text to welcome user. */
|
||||
"Welcome, %@!" = "Hoş geldin, %@";
|
||||
|
||||
/* Placeholder example for relay server address. */
|
||||
"wss://some.relay.com" = "wss://some.relay.com";
|
||||
|
||||
/* 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. */
|
||||
"you" = "sen";
|
||||
|
||||
/* Label for Your Name section of user profile form. */
|
||||
"Your Name" = "İsminiz";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Zebedee. */
|
||||
"Zebedee" = "Zebedee";
|
||||
|
||||
/* Dropdown option label for Lightning wallet, Zeus LN. */
|
||||
"Zeus LN" = "Zeus LN";
|
||||
|
||||
154
damus/tr-TR.lproj/Localizable.stringsdict
Normal file
154
damus/tr-TR.lproj/Localizable.stringsdict
Normal file
@@ -0,0 +1,154 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>collapsed_event_view_other_notes</key>
|
||||
<dict>
|
||||
<key>NOTES</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>1%d diğer not</string>
|
||||
<key>other</key>
|
||||
<string>%d diğer notlar</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>··· %#@NOTES@ ···</string>
|
||||
</dict>
|
||||
<key>followers_count</key>
|
||||
<dict>
|
||||
<key>FOLLOWERS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Takipçi</string>
|
||||
<key>other</key>
|
||||
<string>Takipçiler</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@FOLLOWERS@</string>
|
||||
</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>Tepki</string>
|
||||
<key>other</key>
|
||||
<string>Tepkiler</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>Röle</string>
|
||||
<key>other</key>
|
||||
<string>Röleler</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>replying_to_one_and_others</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%@%#@OTHERS@'lara yanıt </string>
|
||||
<key>OTHERS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>& %d diğer</string>
|
||||
<key>other</key>
|
||||
<string>& %d diğerleri</string>
|
||||
<key>zero</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>replying_to_two_and_others</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%@, %@%#@OTHERS@'a yanıt</string>
|
||||
<key>OTHERS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>& %d diğer</string>
|
||||
<key>other</key>
|
||||
<string>& %d diğerleri</string>
|
||||
<key>zero</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>reposts_count</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@REPOSTS@</string>
|
||||
<key>REPOSTS</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Yineleme</string>
|
||||
<key>other</key>
|
||||
<string>Yinelemeler</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$@ sat</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>Bahşiş</string>
|
||||
<key>other</key>
|
||||
<string>Bahşişler</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
128
damusTests/DMTests.swift
Normal file
128
damusTests/DMTests.swift
Normal file
@@ -0,0 +1,128 @@
|
||||
//
|
||||
// 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 pubkey = "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"
|
||||
let model = DirectMessagesModel(our_pubkey: pubkey)
|
||||
|
||||
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.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -105,6 +105,14 @@ class damusTests: XCTestCase {
|
||||
XCTAssertEqual(parsed[1].is_text, " br")
|
||||
}
|
||||
|
||||
func testNoParseUrlWithOnlyWhitespace() {
|
||||
let testString = "https:// "
|
||||
let parsed = parse_mentions(content: testString, tags: [])
|
||||
|
||||
XCTAssertNotNil(parsed)
|
||||
XCTAssertEqual(parsed[0].is_text, testString)
|
||||
}
|
||||
|
||||
func testParseMentionBlank() {
|
||||
let parsed = parse_mentions(content: "", tags: [["e", "event_id"]])
|
||||
|
||||
@@ -137,6 +145,26 @@ class damusTests: XCTestCase {
|
||||
XCTAssertEqual(parsed[2].is_text, " derp")
|
||||
}
|
||||
|
||||
func testHashtagWithComma() {
|
||||
let parsed = parse_mentions(content: "some hashtag #bitcoin, cool", tags: [])
|
||||
|
||||
XCTAssertNotNil(parsed)
|
||||
XCTAssertEqual(parsed.count, 3)
|
||||
XCTAssertEqual(parsed[0].is_text, "some hashtag ")
|
||||
XCTAssertEqual(parsed[1].is_hashtag, "bitcoin")
|
||||
XCTAssertEqual(parsed[2].is_text, ", cool")
|
||||
}
|
||||
|
||||
func testHashtagWithEmoji() {
|
||||
let parsed = parse_mentions(content: "some hashtag #bitcoin☕️ cool", tags: [])
|
||||
|
||||
XCTAssertNotNil(parsed)
|
||||
XCTAssertEqual(parsed.count, 3)
|
||||
XCTAssertEqual(parsed[0].is_text, "some hashtag ")
|
||||
XCTAssertEqual(parsed[1].is_hashtag, "bitcoin")
|
||||
XCTAssertEqual(parsed[2].is_text, "☕️ cool")
|
||||
}
|
||||
|
||||
func testParseHashtagEnd() {
|
||||
let parsed = parse_mentions(content: "some hashtag #bitcoin", tags: [])
|
||||
|
||||
|
||||
@@ -7,7 +7,4 @@ git:
|
||||
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
|
||||
pr_branch_name: transifex/<br_unique_id>
|
||||
Reference in New Issue
Block a user