Compare commits

..

1 Commits

Author SHA1 Message Date
619ece67be Internationalize time ago since string
Switches to using standard date component formatting abbreviations and enables it to be localized to non-English locales
2022-12-30 23:46:40 -05:00
65 changed files with 301 additions and 1847 deletions

View File

@@ -1,38 +1,5 @@
## [1.0.0] - 2023-01-01
### Added
- Parse links in profiles (Lionello Lunesu)
- Added Breez wallet to wallet selector (Lee Salminen)
- Added Bitcoin Beach wallet to wallet selector (Lee Salminen)
- Added ability to copy relay urls (Matt Ward)
- Added option to choose default wallet (Suhail Saqan)
### Changed
- Switch like from ❤️ to 🤙 (William Casarin)
- Internationalize relative dates (Terry Yiu)
### Fixed
- Fix but where text was not showing after invoices (William Casarin)
- Load profiles in DMs and notifications (William Casarin)
- Fix expanding profile picture (nosestr bug) (Joel Klabo)
- Fix padding on threads and search results views (OlegAba)
- Don't badge DMs if sent by you (Joel Klabo)
- Reset relay in Add Relay view after adding (Joel Klabo)
[1.0.0]: https://github.com/damus-io/damus/releases/tag/v1.0.0
## [0.1.8-9] - 2022-12-29
### Added
- Relay list on user profiles
### Changed
- Show recommended relays in config. Currently just a fixed set. (William Casarin)

View File

@@ -1,804 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 http://docs.oasis-open.org/xliff/v1.2/os/xliff-core-1.2-strict.xsd">
<file original="damus/en.lproj/InfoPlist.strings" source-language="en" target-language="en" datatype="plaintext">
<header>
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="14.2" build-num="14C18"/>
</header>
<body>
<trans-unit id="CFBundleDisplayName" xml:space="preserve">
<source>Damus</source>
<target>Damus</target>
<note>Bundle display name</note>
</trans-unit>
<trans-unit id="CFBundleName" xml:space="preserve">
<source>damus</source>
<target>damus</target>
<note>Bundle name</note>
</trans-unit>
</body>
</file>
<file original="damus/en.lproj/Localizable.strings" source-language="en" target-language="en" datatype="plaintext">
<header>
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="14.2" build-num="14C18"/>
</header>
<body>
<trans-unit id=" " xml:space="preserve">
<source> </source>
<target> </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@" xml:space="preserve">
<source>%@</source>
<target>%@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ following" xml:space="preserve">
<source>%@ following</source>
<target>%@ following</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@'s Followers" xml:space="preserve">
<source>%@'s Followers</source>
<target>%@'s Followers</target>
<note>No comment provided by engineer.</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>
<target>%@. Creating an account doesn't require a phone number, email or name. Get started right away with zero friction.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@. End-to-End encrypted private messaging. Keep Big Tech out of your DMs" xml:space="preserve">
<source>%@. End-to-End encrypted private messaging. Keep Big Tech out of your DMs</source>
<target>%@. End-to-End encrypted private messaging. Keep Big Tech out of your DMs</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@. Tip your friend's posts and stack sats with Bitcoin⚡, the native currency of the internet." xml:space="preserve">
<source>%@. Tip your friend's posts and stack sats with Bitcoin⚡, the native currency of the internet.</source>
<target>%@. Tip your friend's posts and stack sats with Bitcoin⚡, the native currency of the internet.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld" xml:space="preserve">
<source>%lld</source>
<target>%lld</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld/%lld" xml:space="preserve">
<source>%lld/%lld</source>
<target>%lld/%lld</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="&amp;nbsp;" xml:space="preserve">
<source>&amp;nbsp;</source>
<target>&amp;nbsp;</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="+" xml:space="preserve">
<source>+</source>
<target>+</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="&lt; e &gt;" xml:space="preserve">
<source>&lt; e &gt;</source>
<target>&lt; e &gt;</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="@" xml:space="preserve">
<source>@</source>
<target>@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="About" xml:space="preserve">
<source>About</source>
<target>About</target>
<note>Label to prompt for about text entry for user to describe about themself.</note>
</trans-unit>
<trans-unit id="About Me" xml:space="preserve">
<source>About Me</source>
<target>About Me</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Absolute Boss" xml:space="preserve">
<source>Absolute Boss</source>
<target>Absolute Boss</target>
<note>Placeholder text for About Me description.</note>
</trans-unit>
<trans-unit id="Account ID" xml:space="preserve">
<source>Account ID</source>
<target>Account ID</target>
<note>Label to indicate the public ID of the account.</note>
</trans-unit>
<trans-unit id="Add" xml:space="preserve">
<source>Add</source>
<target>Add</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add Relay" xml:space="preserve">
<source>Add Relay</source>
<target>Add Relay</target>
<note>No comment provided by engineer.</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>No comment provided by engineer.</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>
<target>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.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bitcoin Beach" xml:space="preserve">
<source>Bitcoin Beach</source>
<target>Bitcoin Beach</target>
<note>Dropdown option label for Lightning wallet, Bitcoin Beach.</note>
</trans-unit>
<trans-unit id="Bitcoin Lightning Tips" xml:space="preserve">
<source>Bitcoin Lightning Tips</source>
<target>Bitcoin Lightning Tips</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Blixt Wallet" xml:space="preserve">
<source>Blixt Wallet</source>
<target>Blixt Wallet</target>
<note>Dropdown option label for Lightning wallet, Blixt Wallet</note>
</trans-unit>
<trans-unit id="Blue Wallet" xml:space="preserve">
<source>Blue Wallet</source>
<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>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Boosted" xml:space="preserve">
<source>Boosted</source>
<target>Boosted</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Breez" xml:space="preserve">
<source>Breez</source>
<target>Breez</target>
<note>Dropdown option label for Lightning wallet, Breez.</note>
</trans-unit>
<trans-unit id="Broadcast" xml:space="preserve">
<source>Broadcast</source>
<target>Broadcast</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Cancel" xml:space="preserve">
<source>Cancel</source>
<target>Cancel</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Cash App" xml:space="preserve">
<source>Cash App</source>
<target>Cash App</target>
<note>Dropdown option label for Lightning wallet, Cash App.</note>
</trans-unit>
<trans-unit id="Copied" xml:space="preserve">
<source>Copied</source>
<target>Copied</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Copy" xml:space="preserve">
<source>Copy</source>
<target>Copy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Copy Account ID" xml:space="preserve">
<source>Copy Account ID</source>
<target>Copy Account ID</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Copy Image" xml:space="preserve">
<source>Copy Image</source>
<target>Copy Image</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Copy Image URL" xml:space="preserve">
<source>Copy Image URL</source>
<target>Copy Image URL</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Copy LNURL" xml:space="preserve">
<source>Copy LNURL</source>
<target>Copy LNURL</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Copy Note ID" xml:space="preserve">
<source>Copy Note ID</source>
<target>Copy Note ID</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Copy Note JSON" xml:space="preserve">
<source>Copy Note JSON</source>
<target>Copy Note JSON</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Copy Text" xml:space="preserve">
<source>Copy Text</source>
<target>Copy Text</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Copy User ID" xml:space="preserve">
<source>Copy User ID</source>
<target>Copy User ID</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Copy invoice" xml:space="preserve">
<source>Copy invoice</source>
<target>Copy invoice</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create" xml:space="preserve">
<source>Create</source>
<target>Create</target>
<note>Button to create account.</note>
</trans-unit>
<trans-unit id="Create Account" xml:space="preserve">
<source>Create Account</source>
<target>Create Account</target>
<note>Button to create an account.</note>
</trans-unit>
<trans-unit id="Creator(s) of Bitcoin. Absolute legend." xml:space="preserve">
<source>Creator(s) of Bitcoin. Absolute legend.</source>
<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>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Damus" xml:space="preserve">
<source>Damus</source>
<target>Damus</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Default Wallet" xml:space="preserve">
<source>Default Wallet</source>
<target>Default Wallet</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete" xml:space="preserve">
<source>Delete</source>
<target>Delete</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Dismiss" xml:space="preserve">
<source>Dismiss</source>
<target>Dismiss</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Display Name" xml:space="preserve">
<source>Display Name</source>
<target>Display Name</target>
<note>Label to prompt display name entry.</note>
</trans-unit>
<trans-unit id="Done" xml:space="preserve">
<source>Done</source>
<target>Done</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Earn Money" xml:space="preserve">
<source>Earn Money</source>
<target>Earn Money</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Edit" xml:space="preserve">
<source>Edit</source>
<target>Edit</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Edit Profile" xml:space="preserve">
<source>Edit Profile</source>
<target>Edit Profile</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypted" xml:space="preserve">
<source>Encrypted</source>
<target>Encrypted</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypted DMs" xml:space="preserve">
<source>Encrypted DMs</source>
<target>Encrypted DMs</target>
<note>No comment provided by engineer.</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>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error: %@" xml:space="preserve">
<source>Error: %@</source>
<target>Error: %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Filter State" xml:space="preserve">
<source>Filter State</source>
<target>Filter State</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Follow" xml:space="preserve">
<source>Follow</source>
<target>Follow</target>
<note>Button to follow a user.</note>
</trans-unit>
<trans-unit id="Followers" xml:space="preserve">
<source>Followers</source>
<target>Followers</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Following" xml:space="preserve">
<source>Following</source>
<target>Following</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Following..." xml:space="preserve">
<source>Following...</source>
<target>Following...</target>
<note>Label to indicate that the user is in the process of following another user.</note>
</trans-unit>
<trans-unit id="Follows" xml:space="preserve">
<source>Follows</source>
<target>Follows</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Global" xml:space="preserve">
<source>Global</source>
<target>Global</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Goto post %@" xml:space="preserve">
<source>Goto post %@</source>
<target>Goto post %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Goto profile %@" xml:space="preserve">
<source>Goto profile %@</source>
<target>Goto profile %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Home" xml:space="preserve">
<source>Home</source>
<target>Home</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="LNLink" xml:space="preserve">
<source>LNLink</source>
<target>LNLink</target>
<note>Dropdown option label for Lightning wallet, LNLink.</note>
</trans-unit>
<trans-unit id="Let's go!" xml:space="preserve">
<source>Let's go!</source>
<target>Let's go!</target>
<note>Button to complete account creation and start using the app.</note>
</trans-unit>
<trans-unit id="Lightning Address or LNURL" xml:space="preserve">
<source>Lightning Address or LNURL</source>
<target>Lightning Address or LNURL</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Lightning Invoice" xml:space="preserve">
<source>Lightning Invoice</source>
<target>Lightning Invoice</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Local default" xml:space="preserve">
<source>Local default</source>
<target>Local default</target>
<note>Dropdown option label for system default for Lightning wallet.</note>
</trans-unit>
<trans-unit id="Login" xml:space="preserve">
<source>Login</source>
<target>Login</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Logout" xml:space="preserve">
<source>Logout</source>
<target>Logout</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Make sure your nsec account key is saved before you logout or you will lose access to this account" xml:space="preserve">
<source>Make sure your nsec account key is saved before you logout or you will lose access to this account</source>
<target>Make sure your nsec account key is saved before you logout or you will lose access to this account</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Muun" xml:space="preserve">
<source>Muun</source>
<target>Muun</target>
<note>Dropdown option label for Lightning wallet, Muun.</note>
</trans-unit>
<trans-unit id="NIP-05 Verification" xml:space="preserve">
<source>NIP-05 Verification</source>
<target>NIP-05 Verification</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Nothing to see here. Check back later!" xml:space="preserve">
<source>Nothing to see here. Check back later!</source>
<target>Nothing to see here. Check back later!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications" xml:space="preserve">
<source>Notifications</source>
<target>Notifications</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Pay" xml:space="preserve">
<source>Pay</source>
<target>Pay</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Pay the lightning invoice" xml:space="preserve">
<source>Pay the lightning invoice</source>
<target>Pay the lightning invoice</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Phoenix" xml:space="preserve">
<source>Phoenix</source>
<target>Phoenix</target>
<note>Dropdown option label for Lightning wallet, Phoenix.</note>
</trans-unit>
<trans-unit id="Post" xml:space="preserve">
<source>Post</source>
<target>Post</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Posts" xml:space="preserve">
<source>Posts</source>
<target>Posts</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Posts &amp; Replies" xml:space="preserve">
<source>Posts &amp; Replies</source>
<target>Posts &amp; Replies</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private" xml:space="preserve">
<source>Private</source>
<target>Private</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private Key" xml:space="preserve">
<source>Private Key</source>
<target>Private Key</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PrivateKey" xml:space="preserve">
<source>PrivateKey</source>
<target>PrivateKey</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile Picture" xml:space="preserve">
<source>Profile Picture</source>
<target>Profile Picture</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Public Account ID" xml:space="preserve">
<source>Public Account ID</source>
<target>Public Account ID</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Public Key" xml:space="preserve">
<source>Public Key</source>
<target>Public Key</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Public Key?" xml:space="preserve">
<source>Public Key?</source>
<target>Public Key?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Recommended Relays" xml:space="preserve">
<source>Recommended Relays</source>
<target>Recommended Relays</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Relay" xml:space="preserve">
<source>Relay</source>
<target>Relay</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Relays" xml:space="preserve">
<source>Relays</source>
<target>Relays</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reply to self" xml:space="preserve">
<source>Reply to self</source>
<target>Reply to self</target>
<note>Label to indicate that the user is replying to themself.</note>
</trans-unit>
<trans-unit id="Replying to:" xml:space="preserve">
<source>Replying to:</source>
<target>Replying to:</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reset" xml:space="preserve">
<source>Reset</source>
<target>Reset</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="River" xml:space="preserve">
<source>River</source>
<target>River</target>
<note>Dropdown option label for Lightning wallet, River</note>
</trans-unit>
<trans-unit id="Satoshi Nakamoto" xml:space="preserve">
<source>Satoshi Nakamoto</source>
<target>Satoshi Nakamoto</target>
<note>Name of Bitcoin creator(s).</note>
</trans-unit>
<trans-unit id="Save" xml:space="preserve">
<source>Save</source>
<target>Save</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Search hashtag: #%@" xml:space="preserve">
<source>Search hashtag: #%@</source>
<target>Search hashtag: #%@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Search..." xml:space="preserve">
<source>Search...</source>
<target>Search...</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Secret Account Login Key" xml:space="preserve">
<source>Secret Account Login Key</source>
<target>Secret Account Login Key</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Select a lightning wallet" xml:space="preserve">
<source>Select a lightning wallet</source>
<target>Select a lightning wallet</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Select default wallet" xml:space="preserve">
<source>Select default wallet</source>
<target>Select default wallet</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send a message to start the conversation..." xml:space="preserve">
<source>Send a message to start the conversation...</source>
<target>Send a message to start the conversation...</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Settings" xml:space="preserve">
<source>Settings</source>
<target>Settings</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share" xml:space="preserve">
<source>Share</source>
<target>Share</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show" xml:space="preserve">
<source>Show</source>
<target>Show</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show wallet selector" xml:space="preserve">
<source>Show wallet selector</source>
<target>Show wallet selector</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Strike" xml:space="preserve">
<source>Strike</source>
<target>Strike</target>
<note>Dropdown option label for Lightning wallet, Strike.</note>
</trans-unit>
<trans-unit id="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." xml:space="preserve">
<source>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.</source>
<target>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.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="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." xml:space="preserve">
<source>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.</source>
<target>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.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This is your account ID, you can give this to your friends so that they can follow you. Click to copy." xml:space="preserve">
<source>This is your account ID, you can give this to your friends so that they can follow you. Click to copy.</source>
<target>This is your account ID, you can give this to your friends so that they can follow you. Click to copy.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="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!" xml:space="preserve">
<source>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!</source>
<target>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!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Thread" xml:space="preserve">
<source>Thread</source>
<target>Thread</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Type your post here..." xml:space="preserve">
<source>Type your post here...</source>
<target>Type your post here...</target>
<note>Text box prompt to ask user to type their post.</note>
</trans-unit>
<trans-unit id="Unfollow" xml:space="preserve">
<source>Unfollow</source>
<target>Unfollow</target>
<note>Button to unfollow a user.</note>
</trans-unit>
<trans-unit id="Unfollowing" xml:space="preserve">
<source>Unfollowing</source>
<target>Unfollowing</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unfollowing..." xml:space="preserve">
<source>Unfollowing...</source>
<target>Unfollowing...</target>
<note>Label to indicate that the user is in the process of unfollowing another user.</note>
</trans-unit>
<trans-unit id="Unfollows" xml:space="preserve">
<source>Unfollows</source>
<target>Unfollows</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Username" xml:space="preserve">
<source>Username</source>
<target>Username</target>
<note>Label to prompt username entry.</note>
</trans-unit>
<trans-unit id="Wallet Of Satoshi" xml:space="preserve">
<source>Wallet Of Satoshi</source>
<target>Wallet Of Satoshi</target>
<note>Dropdown option label for Lightning wallet, Wallet Of Satoshi.</note>
</trans-unit>
<trans-unit id="Wallet Selector" xml:space="preserve">
<source>Wallet Selector</source>
<target>Wallet Selector</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Website" xml:space="preserve">
<source>Website</source>
<target>Website</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Welcome to the social network %@ control." xml:space="preserve">
<source>Welcome to the social network %@ control.</source>
<target>Welcome to the social network %@ control.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Welcome, %@!" xml:space="preserve">
<source>Welcome, %@!</source>
<target>Welcome, %@!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your Name" xml:space="preserve">
<source>Your Name</source>
<target>Your Name</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Zebedee" xml:space="preserve">
<source>Zebedee</source>
<target>Zebedee</target>
<note>Dropdown option label for Lightning wallet, Zebedee.</note>
</trans-unit>
<trans-unit id="Zeus LN" xml:space="preserve">
<source>Zeus LN</source>
<target>Zeus LN</target>
<note>Dropdown option label for Lightning wallet, Zeus LN.</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>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="https://jb55.com" xml:space="preserve">
<source>https://jb55.com</source>
<target>https://jb55.com</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="jb55@jb55.com" xml:space="preserve">
<source>jb55@jb55.com</source>
<target>jb55@jb55.com</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="none" xml:space="preserve">
<source>none</source>
<target>none</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="now" xml:space="preserve">
<source>now</source>
<target>now</target>
<note>String indicating that a given timestamp just occurred</note>
</trans-unit>
<trans-unit id="optional" xml:space="preserve">
<source>optional</source>
<target>optional</target>
<note>No comment provided by engineer.</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>
<note>Label to indicate that the user is replying to 1 user and others. (Key in .stringsdict)</note>
</trans-unit>
<trans-unit id="replying_to_two_and_others" translate="no" xml:space="preserve">
<source>replying_to_two_and_others</source>
<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="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="wss://some.relay.com" xml:space="preserve">
<source>wss://some.relay.com</source>
<target>wss://some.relay.com</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="you" xml:space="preserve">
<source>you</source>
<target>you</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="··· %lld other notes ···" xml:space="preserve">
<source>··· %lld other notes ···</source>
<target>··· %lld other notes ···</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="🤙" xml:space="preserve">
<source>🤙</source>
<target>🤙</target>
<note>No comment provided by engineer.</note>
</trans-unit>
</body>
</file>
<file original="damus/en.lproj/Localizable.stringsdict" source-language="en" target-language="en" datatype="plaintext">
<header>
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="14.2" build-num="14C18"/>
</header>
<body>
<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> &amp; 1 other</source>
<target> &amp; 1 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">
<source> &amp; %d others</source>
<target> &amp; %d 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/zero:dict/:string" xml:space="preserve">
<source/>
<target/>
<note>Label to indicate that the user is replying to 1 user and others.</note>
</trans-unit>
<trans-unit id="/replying_to_two_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 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> &amp; 1 other</source>
<target> &amp; 1 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">
<source> &amp; %d others</source>
<target> &amp; %d others</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/zero:dict/:string" xml:space="preserve">
<source/>
<target/>
<note>Label to indicate that the user is replying to 2 users and others.</note>
</trans-unit>
</body>
</file>
</xliff>

View File

@@ -1,4 +0,0 @@
/* Bundle display name */
"CFBundleDisplayName" = "Damus";
/* Bundle name */
"CFBundleName" = "damus";

View File

@@ -1,42 +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> &amp; 1 other</string>
<key>other</key>
<string> &amp; %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> &amp; 1 other</string>
<key>other</key>
<string> &amp; %d others</string>
</dict>
</dict>
</dict>
</plist>

View File

@@ -1,12 +0,0 @@
{
"developmentRegion" : "en",
"project" : "damus.xcodeproj",
"targetLocale" : "en",
"toolInfo" : {
"toolBuildNumber" : "14C18",
"toolID" : "com.apple.dt.xcode",
"toolName" : "Xcode",
"toolVersion" : "14.2"
},
"version" : "1.0"
}

View File

@@ -151,7 +151,7 @@ static bool from_numbers(u64 *res,
return false;
if (!from_number(&p1, s1, len1, tens_factor)
|| !from_number(&p2, s2, len2, tens_factor - (int)len2))
|| !from_number(&p2, s2, len2, tens_factor - len2))
return false;
if (add_overflows_u64(p1, p2))
@@ -453,7 +453,7 @@ bool amount_msat_to_u32(struct amount_msat msat, u32 *millisatoshis)
{
if (amount_msat_greater_eq(msat, AMOUNT_MSAT(0x100000000)))
return false;
*millisatoshis = (u32)msat.millisatoshis;
*millisatoshis = msat.millisatoshis;
return true;
}

View File

@@ -297,7 +297,7 @@ static char *decode_c(struct bolt11 *b11,
if (!pull_uint(hu5, data, data_len, &c, data_length * 5))
return tal_fmt(b11, "c: length %zu chars is excessive",
*data_len);
b11->min_final_cltv_expiry = (u32)c;
b11->min_final_cltv_expiry = c;
/* Can overflow, since c is 64 bits but value must be < 32 bits */
if (b11->min_final_cltv_expiry != c)
return tal_fmt(b11, "c: %"PRIu64" is too large", c);

View File

@@ -241,7 +241,7 @@ static int parse_invoice(struct cursor *cur, struct block *block) {
block->block.invoice.invstr.end = (const char*)end;
block->block.invoice.bolt11 = bolt11;
cur->p = end;
cur->p += end - start;
return 1;
}

View File

@@ -30,7 +30,7 @@ void hash_u5(struct hash_u5 *hu5, const u8 *u5, size_t len)
u5++;
if (hu5->num_bits >= 32) {
be32 be32 = cpu_to_be32((u32)(hu5->buf >> (hu5->num_bits-32)));
be32 be32 = cpu_to_be32(hu5->buf >> (hu5->num_bits-32));
sha256_update(&hu5->hash, &be32, sizeof(be32));
hu5->num_bits -= 32;
}
@@ -40,7 +40,7 @@ void hash_u5(struct hash_u5 *hu5, const u8 *u5, size_t len)
void hash_u5_done(struct hash_u5 *hu5, struct sha256 *res)
{
if (hu5->num_bits) {
be32 be32 = cpu_to_be32((u32)(hu5->buf << (32 - hu5->num_bits)));
be32 be32 = cpu_to_be32(hu5->buf << (32 - hu5->num_bits));
sha256_update(&hu5->hash, &be32, (hu5->num_bits + 7) / 8);
}

View File

@@ -37,7 +37,7 @@ static inline bool assign_overflow_u16(u16 *dst, uint64_t v)
static inline bool assign_overflow_u32(u32 *dst, uint64_t v)
{
*dst = (u32)v;
*dst = v;
return *dst == v;
}
#endif /* LIGHTNING_COMMON_OVERFLOWS_H */

View File

@@ -11,9 +11,6 @@
3169CAE6294E69C000EE4006 /* EmptyTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3169CAE5294E69C000EE4006 /* EmptyTimelineView.swift */; };
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 */; };
3AB18056296375CA00FD1BD8 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3AB18052296375CA00FD1BD8 /* InfoPlist.strings */; };
3AB18057296375CA00FD1BD8 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3AB18054296375CA00FD1BD8 /* 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 */; };
@@ -52,7 +49,6 @@
4C363AA228296A7E006E126D /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363AA128296A7E006E126D /* SearchView.swift */; };
4C363AA428296DEE006E126D /* SearchModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363AA328296DEE006E126D /* SearchModel.swift */; };
4C363AA828297703006E126D /* InsertSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363AA728297703006E126D /* InsertSort.swift */; };
4C3A1D332960DB0500558C0F /* Markdown.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3A1D322960DB0500558C0F /* Markdown.swift */; };
4C3AC79B28306D7B00E1F516 /* Contacts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3AC79A28306D7B00E1F516 /* Contacts.swift */; };
4C3AC79D2833036D00E1F516 /* FollowingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3AC79C2833036D00E1F516 /* FollowingView.swift */; };
4C3AC79F2833115300E1F516 /* FollowButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3AC79E2833115300E1F516 /* FollowButtonView.swift */; };
@@ -137,9 +133,7 @@
4CEE2AF7280B2DEA00AB5EEF /* ProfileName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2AF6280B2DEA00AB5EEF /* ProfileName.swift */; };
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 */; };
6C7DE41F2955169800E66263 /* Vault in Frameworks */ = {isa = PBXBuildFile; productRef = 6C7DE41E2955169800E66263 /* Vault */; };
BA693074295D649800ADDB87 /* UserSettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA693073295D649800ADDB87 /* UserSettingsStore.swift */; };
BAB68BED29543FA3007BA466 /* SelectWalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */; };
E990020F2955F837003BBC5A /* EditMetadataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E990020E2955F837003BBC5A /* EditMetadataView.swift */; };
E9E4ED0B295867B900DD7078 /* ThreadV2View.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E4ED0A295867B900DD7078 /* ThreadV2View.swift */; };
@@ -167,13 +161,6 @@
3169CAE5294E69C000EE4006 /* EmptyTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyTimelineView.swift; sourceTree = "<group>"; };
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>"; };
3A4325A92961E11400BFCD9D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
3AB1803D29636FB100FD1BD8 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = es; path = es.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
3AB18058296377E500FD1BD8 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = "<group>"; };
3AB18059296377E700FD1BD8 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
3AB1805A2963EF7E00FD1BD8 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = "<group>"; };
3AB1805B2963EF7E00FD1BD8 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
3AB1805C2963EF7E00FD1BD8 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = fr; path = fr.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
3ACBCB77295FE5C70037388A /* TimeAgoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeAgoTests.swift; 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>"; };
@@ -214,7 +201,6 @@
4C363AA128296A7E006E126D /* SearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchView.swift; sourceTree = "<group>"; };
4C363AA328296DEE006E126D /* SearchModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchModel.swift; sourceTree = "<group>"; };
4C363AA728297703006E126D /* InsertSort.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsertSort.swift; sourceTree = "<group>"; };
4C3A1D322960DB0500558C0F /* Markdown.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Markdown.swift; sourceTree = "<group>"; };
4C3AC79A28306D7B00E1F516 /* Contacts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Contacts.swift; sourceTree = "<group>"; };
4C3AC79C2833036D00E1F516 /* FollowingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowingView.swift; sourceTree = "<group>"; };
4C3AC79E2833115300E1F516 /* FollowButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowButtonView.swift; sourceTree = "<group>"; };
@@ -332,8 +318,6 @@
4CEE2AF6280B2DEA00AB5EEF /* ProfileName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileName.swift; sourceTree = "<group>"; };
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>"; };
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>"; };
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>"; };
@@ -460,8 +444,6 @@
4C64987D286D082C00EAE2B3 /* DirectMessagesModel.swift */,
4C216F372871EDE300040376 /* DirectMessageModel.swift */,
4C99737A28C92A9200E53835 /* ChatroomMetadata.swift */,
BA693073295D649800ADDB87 /* UserSettingsStore.swift */,
4FE60CDC295E1C5E00105A1F /* Wallet.swift */,
);
path = Models;
sourceTree = "<group>";
@@ -539,7 +521,6 @@
4C7FF7D628233637009601DB /* Util */ = {
isa = PBXGroup;
children = (
4C3A1D322960DB0500558C0F /* Markdown.swift */,
4CEE2AF4280B29E600AB5EEF /* TimeAgo.swift */,
4CE4F8CC281352B30009DFBB /* Notifications.swift */,
4C363A8328233689006E126D /* Parser.swift */,
@@ -603,9 +584,6 @@
4CE6DEE827F7A08100C66700 /* ContentView.swift */,
4CE6DEEA27F7A08200C66700 /* Assets.xcassets */,
4CE6DEEC27F7A08200C66700 /* Preview Content */,
3AB18052296375CA00FD1BD8 /* InfoPlist.strings */,
3AB18054296375CA00FD1BD8 /* Localizable.strings */,
3A4325AA2961E11400BFCD9D /* Localizable.stringsdict */,
);
path = damus;
sourceTree = "<group>";
@@ -741,8 +719,6 @@
knownRegions = (
en,
Base,
es,
fr,
);
mainGroup = 4CE6DEDA27F7A08100C66700;
packageReferences = (
@@ -768,11 +744,8 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
3AB18057296375CA00FD1BD8 /* Localizable.strings in Resources */,
4CE6DEEE27F7A08200C66700 /* Preview Assets.xcassets in Resources */,
3AB18056296375CA00FD1BD8 /* InfoPlist.strings in Resources */,
4CE6DEEB27F7A08200C66700 /* Assets.xcassets in Resources */,
3A4325A82961E11400BFCD9D /* Localizable.stringsdict in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -836,7 +809,6 @@
4C363A8428233689006E126D /* Parser.swift in Sources */,
4CE4F9E328528C5200C00DD9 /* AddRelayView.swift in Sources */,
4C363A9A28283854006E126D /* Reply.swift in Sources */,
BA693074295D649800ADDB87 /* UserSettingsStore.swift in Sources */,
4C90BD18283A9EE5008EE7EF /* LoginView.swift in Sources */,
4C3EA66828FF5F9900C48A62 /* hex.c in Sources */,
E9E4ED0B295867B900DD7078 /* ThreadV2View.swift in Sources */,
@@ -905,10 +877,8 @@
4C90BD1A283AA67F008EE7EF /* Bech32.swift in Sources */,
E990020F2955F837003BBC5A /* EditMetadataView.swift in Sources */,
4CACA9D5280C31E100D9BBE8 /* ReplyView.swift in Sources */,
4C3A1D332960DB0500558C0F /* Markdown.swift in Sources */,
4C0A3F97280F8E02000448DE /* ThreadView.swift in Sources */,
4C06670B28FDE64700038D2A /* damus.c in Sources */,
4FE60CDD295E1C5E00105A1F /* Wallet.swift in Sources */,
4C99737B28C92A9200E53835 /* ChatroomMetadata.swift in Sources */,
4C75EFA427FA577B0006080F /* PostView.swift in Sources */,
4C75EFB528049D790006080F /* Relay.swift in Sources */,
@@ -956,43 +926,11 @@
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
3A4325AA2961E11400BFCD9D /* Localizable.stringsdict */ = {
isa = PBXVariantGroup;
children = (
3A4325A92961E11400BFCD9D /* en */,
3AB1803D29636FB100FD1BD8 /* es */,
3AB1805C2963EF7E00FD1BD8 /* fr */,
);
name = Localizable.stringsdict;
sourceTree = "<group>";
};
3AB18052296375CA00FD1BD8 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
3AB18058296377E500FD1BD8 /* es */,
3AB1805A2963EF7E00FD1BD8 /* fr */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
3AB18054296375CA00FD1BD8 /* Localizable.strings */ = {
isa = PBXVariantGroup;
children = (
3AB18059296377E700FD1BD8 /* es */,
3AB1805B2963EF7E00FD1BD8 /* fr */,
);
name = Localizable.strings;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
4CE6DF0527F7A08200C66700 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
@@ -1039,7 +977,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.3;
MACOSX_DEPLOYMENT_TARGET = 12.3;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
@@ -1054,7 +992,6 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
@@ -1095,7 +1032,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.3;
MACOSX_DEPLOYMENT_TARGET = 12.3;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
@@ -1114,14 +1051,13 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = damus/damus.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 9;
DEVELOPMENT_ASSET_PATHS = "\"damus/Preview Content\"";
DEVELOPMENT_TEAM = XK7H4JAB3D;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = damus/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Damus;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
@@ -1135,7 +1071,7 @@
"$(inherited)",
"$(PROJECT_DIR)",
);
MARKETING_VERSION = 1.0.0;
MARKETING_VERSION = 0.1.8;
PRODUCT_BUNDLE_IDENTIFIER = com.jb55.damus2;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
@@ -1154,14 +1090,13 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = damus/damus.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 9;
DEVELOPMENT_ASSET_PATHS = "\"damus/Preview Content\"";
DEVELOPMENT_TEAM = XK7H4JAB3D;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = damus/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Damus;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
@@ -1175,7 +1110,7 @@
"$(inherited)",
"$(PROJECT_DIR)",
);
MARKETING_VERSION = 1.0.0;
MARKETING_VERSION = 0.1.8;
PRODUCT_BUNDLE_IDENTIFIER = com.jb55.damus2;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -1,21 +0,0 @@
{
"images" : [
{
"filename" : "blixt-wallet.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 215 KiB

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -7,42 +7,18 @@
import SwiftUI
func open_with_wallet(wallet: Wallet.Model, invoice: String) {
if let url = URL(string: "\(wallet.link)\(invoice)"), UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
} else {
guard let store_link = wallet.appStoreLink else {
// TODO: do something here if we don't have an appstore link
return
}
guard let url = URL(string: store_link) else {
return
}
guard UIApplication.shared.canOpenURL(url) else {
return
}
UIApplication.shared.open(url)
}
}
struct InvoiceView: View {
@Environment(\.colorScheme) var colorScheme
@Environment(\.openURL) private var openURL
let invoice: Invoice
@State var showing_select_wallet: Bool = false
@ObservedObject var user_settings = UserSettingsStore()
@State var showingSelectWallet: Bool = false
@State var inv: String = ""
var PayButton: some View {
Button {
if user_settings.show_wallet_selector {
showing_select_wallet = true
} else {
open_with_wallet(wallet: user_settings.default_wallet.model, invoice: invoice.string)
}
inv = invoice.string
showingSelectWallet = true
} label: {
RoundedRectangle(cornerRadius: 20)
.foregroundColor(colorScheme == .light ? .black : .white)
@@ -71,7 +47,7 @@ struct InvoiceView: View {
}
Divider()
Text(invoice.description)
Text(invoice.amount.amount_sats_str())
Text("\(invoice.amount / 1000) sats")
.font(.title)
PayButton
.frame(height: 50)
@@ -79,13 +55,13 @@ struct InvoiceView: View {
}
.padding(30)
}
.sheet(isPresented: $showing_select_wallet, onDismiss: {showing_select_wallet = false}) {
SelectWalletView(showingSelectWallet: $showing_select_wallet, invoice: invoice.string).environmentObject(user_settings)
.sheet(isPresented: $showingSelectWallet, onDismiss: {showingSelectWallet = false}) {
SelectWalletView(showingSelectWallet: $showingSelectWallet, invoice: $inv)
}
}
}
let test_invoice = Invoice(description: "this is a description", amount: .specific(10000), string: "lnbc100n1p357sl0sp5t9n56wdztun39lgdqlr30xqwksg3k69q4q2rkr52aplujw0esn0qpp5mrqgljk62z20q4nvgr6lzcyn6fhylzccwdvu4k77apg3zmrkujjqdpzw35xjueqd9ejqcfqv3jhxcmjd9c8g6t0dcxqyjw5qcqpjrzjqt56h4gvp5yx36u2uzqa6qwcsk3e2duunfxppzj9vhypc3wfe2wswz607uqq3xqqqsqqqqqqqqqqqlqqyg9qyysgqagx5h20aeulj3gdwx3kxs8u9f4mcakdkwuakasamm9562ffyr9en8yg20lg0ygnr9zpwp68524kmda0t5xp2wytex35pu8hapyjajxqpsql29r", expiry: 604800, payment_hash: Data(), created_at: 1666139119)
let test_invoice = Invoice(description: "this is a description", amount: 10000, string: "lnbc100n1p357sl0sp5t9n56wdztun39lgdqlr30xqwksg3k69q4q2rkr52aplujw0esn0qpp5mrqgljk62z20q4nvgr6lzcyn6fhylzccwdvu4k77apg3zmrkujjqdpzw35xjueqd9ejqcfqv3jhxcmjd9c8g6t0dcxqyjw5qcqpjrzjqt56h4gvp5yx36u2uzqa6qwcsk3e2duunfxppzj9vhypc3wfe2wswz607uqq3xqqqsqqqqqqqqqqqlqqyg9qyysgqagx5h20aeulj3gdwx3kxs8u9f4mcakdkwuakasamm9562ffyr9en8yg20lg0ygnr9zpwp68524kmda0t5xp2wytex35pu8hapyjajxqpsql29r", expiry: 604800, payment_hash: Data(), created_at: 1666139119)
struct InvoiceView_Previews: PreviewProvider {
static var previews: some View {

View File

@@ -30,7 +30,7 @@ struct InvoicesView: View {
struct InvoicesView_Previews: PreviewProvider {
static var previews: some View {
InvoicesView(invoices: [Invoice.init(description: "description", amount: .specific(10000), string: "invstr", expiry: 100000, payment_hash: Data(), created_at: 1000000)])
InvoicesView(invoices: [Invoice.init(description: "description", amount: 10000, string: "invstr", expiry: 100000, payment_hash: Data(), created_at: 1000000)])
.frame(width: 300)
}
}

View File

@@ -16,7 +16,7 @@ var BOOTSTRAP_RELAYS = [
"wss://relay.nostr.bg",
"wss://nostr.oxtr.dev",
"wss://nostr.v0l.io",
"wss://brb.io",
"wss://nostr-2.zebedee.cloud",
]
struct TimestampedProfile {
@@ -72,7 +72,6 @@ struct ContentView: View {
@State var search_open: Bool = false
@State var filter_state : FilterState = .posts_and_replies
@StateObject var home: HomeModel = HomeModel()
@StateObject var user_settings = UserSettingsStore()
// connect retry timer
let timer = Timer.publish(every: 4, on: .main, in: .common).autoconnect()
@@ -83,13 +82,16 @@ struct ContentView: View {
var PostingTimelineView: some View {
VStack{
TabView(selection: $filter_state) {
ContentTimelineView
.tag(FilterState.posts)
ContentTimelineView
.tag(FilterState.posts_and_replies)
ZStack {
if let damus = self.damus_state {
TimelineView(events: $home.events, loading: $home.loading, damus: damus, show_friend_icon: false, filter: filter_event)
}
.tabViewStyle(.page(indexDisplayMode: .never))
if privkey != nil {
PostButtonContainer {
self.active_sheet = .post
}
}
}.ignoresSafeArea(.keyboard, edges: .bottom)
}
.safeAreaInset(edge: .top) {
VStack(spacing: 0) {
@@ -103,19 +105,6 @@ struct ContentView: View {
}
}
var ContentTimelineView: some View {
ZStack {
if let damus = self.damus_state {
TimelineView(events: $home.events, loading: $home.loading, damus: damus, show_friend_icon: false, filter: filter_event)
}
if privkey != nil {
PostButtonContainer {
self.active_sheet = .post
}
}
}
}
var FiltersView: some View {
VStack{
Picker("Filter State", selection: $filter_state) {
@@ -230,7 +219,7 @@ struct ContentView: View {
.foregroundColor(.gray)
}
NavigationLink(destination: ConfigView(state: damus_state!).environmentObject(user_settings)) {
NavigationLink(destination: ConfigView(state: damus_state!)) {
Label("", systemImage: "gear")
}
.buttonStyle(PlainButtonStyle())

View File

@@ -17,9 +17,6 @@
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>river</string>
<string>bitcoinbeach</string>
<string>breez</string>
<string>muun</string>
<string>zeusln</string>
<string>zebedee</string>
@@ -30,7 +27,6 @@
<string>strike</string>
<string>bluewallet</string>
<string>walletofsatoshi</string>
<string>blixtwallet</string>
</array>
<key>NSAppTransportSecurity</key>
<dict>

View File

@@ -44,7 +44,6 @@ class HomeModel: ObservableObject {
let notifications_subid = UUID().description
let dms_subid = UUID().description
let init_subid = UUID().description
let profiles_subid = UUID().description
@Published var new_events: NewEventsBits = NewEventsBits()
@Published var notifications: [NostrEvent] = []
@@ -235,15 +234,7 @@ class HomeModel: ObservableObject {
//self.events.insert(NostrEvent(content: "NOTICE from \(relay_id): \(msg)", pubkey: "system"), at: 0)
print(msg)
case .eose(let sub_id):
if sub_id == dms_subid {
let dms = dms.dms.flatMap { $0.1.events }
load_profiles(profiles_subid: profiles_subid, relay_id: relay_id, events: dms, damus_state: damus_state)
} else if sub_id == notifications_subid {
load_profiles(profiles_subid: profiles_subid, relay_id: relay_id, events: notifications, damus_state: damus_state)
}
case .eose:
self.loading = false
break
}
@@ -347,16 +338,14 @@ class HomeModel: ObservableObject {
return m[kind]
}
func handle_last_event(ev: NostrEvent, timeline: Timeline, shouldNotify: Bool = true) {
func handle_last_event(ev: NostrEvent, timeline: Timeline) {
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) {
if !insert_uniq_sorted_event(events: &notifications, new_ev: ev, cmp: { $0.created_at > $1.created_at }) {
@@ -426,13 +415,13 @@ class HomeModel: ObservableObject {
}
if inserted {
handle_last_event(ev: ev, timeline: .dms, shouldNotify: !ours)
handle_last_event(ev: ev, timeline: .dms)
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
return true
}
}
}

View File

@@ -34,7 +34,7 @@ struct IdBlock: Identifiable {
struct Invoice {
let description: String
let amount: Amount
let amount: Int64
let string: String
let expiry: UInt64
let payment_hash: Data
@@ -115,7 +115,7 @@ func parse_mentions(content: String, tags: [[String]]) -> [Block] {
blocks_init(&bs)
let bytes = content.utf8CString
let _ = bytes.withUnsafeBufferPointer { p in
bytes.withUnsafeBufferPointer { p in
damus_parse_content(&bs, p.baseAddress)
}
@@ -180,23 +180,6 @@ func maybe_pointee<T>(_ p: UnsafeMutablePointer<T>!) -> T? {
return p.pointee
}
enum Amount: Equatable {
case any
case specific(Int64)
func amount_sats_str() -> String {
switch self {
case .any:
return "Any"
case .specific(let amt):
if amt < 1000 {
return "\(Double(amt) / 1000.0) sats"
}
return "\(amt / 1000) sats"
}
}
}
func convert_invoice_block(_ b: invoice_block) -> Block? {
guard let invstr = strblock_to_string(b.invstr) else {
return nil
@@ -211,8 +194,12 @@ func convert_invoice_block(_ b: invoice_block) -> Block? {
description = String(cString: b11.description)
}
let amount: Amount = maybe_pointee(b11.msat).map { .specific(Int64($0.millisatoshis)) } ?? .any
guard let msat = maybe_pointee(b11.msat) else {
return nil
}
let amount = Int64(msat.millisatoshis)
let payment_hash = Data(bytes: &b11.payment_hash, count: 32)
let hex = hex_encode(payment_hash)
let created_at = b11.timestamp
tal_free(b.bolt11)

View File

@@ -61,7 +61,7 @@ class ProfileModel: ObservableObject, Equatable {
profile_filter.authors = [pubkey]
text_filter.authors = [pubkey]
text_filter.limit = 500
text_filter.limit = 1000
print("subscribing to profile \(pubkey) with sub_id \(sub_id)")
print_filters(relay_id: "profile", filters: [[text_filter], [profile_filter]])
@@ -70,18 +70,12 @@ class ProfileModel: ObservableObject, Equatable {
}
func handle_profile_contact_event(_ ev: NostrEvent) {
process_contact_event(pool: damus.pool, contacts: damus.contacts, pubkey: damus.pubkey, ev: ev)
// only use new stuff
if let current_ev = self.contacts {
guard ev.created_at > current_ev.created_at else {
return
}
}
self.contacts = ev
self.following = count_pubkeys(ev.tags)
self.relays = decode_json_relays(ev.content)
if damus.contacts.is_friend(ev.pubkey) {
self.damus.contacts.add_friend_contact(ev)
}
}
func add_event(_ ev: NostrEvent) {
@@ -96,8 +90,6 @@ class ProfileModel: ObservableObject, Equatable {
let _ = insert_uniq_sorted_event(events: &self.events, new_ev: ev, cmp: { $0.created_at > $1.created_at})
} else if ev.known_kind == .contacts {
handle_profile_contact_event(ev)
} else if ev.known_kind == .metadata {
process_metadata_event(profiles: damus.profiles, ev: ev)
}
seen_event.insert(ev.id)
}

View File

@@ -1,32 +0,0 @@
//
// UserSettingsStore.swift
// damus
//
// Created by Suhail Saqan on 12/29/22.
//
import Foundation
class UserSettingsStore: ObservableObject {
@Published var default_wallet: Wallet {
didSet {
UserDefaults.standard.set(default_wallet.rawValue, forKey: "default_wallet")
}
}
@Published var show_wallet_selector: Bool {
didSet {
UserDefaults.standard.set(show_wallet_selector, forKey: "show_wallet_selector")
}
}
init() {
if let defaultWalletName = UserDefaults.standard.string(forKey: "default_wallet"),
let default_wallet = Wallet(rawValue: defaultWalletName) {
self.default_wallet = default_wallet
} else {
self.default_wallet = .system_default_wallet
}
self.show_wallet_selector = UserDefaults.standard.object(forKey: "show_wallet_selector") as? Bool ?? true
}
}

View File

@@ -1,89 +0,0 @@
//
// Wallet.swift
// damus
//
// Created by Benjamin Hakes on 12/29/22.
//
import Foundation
enum Wallet: String, CaseIterable, Identifiable {
var id: String { self.rawValue }
struct Model: Identifiable, Hashable {
var id: String { self.tag }
var index: Int
var tag: String
var displayName : String
var link : String
var appStoreLink : String?
var image: String
}
// New url prefixes needed to be added to LSApplicationQueriesSchemes
case system_default_wallet
case strike
case cashapp
case muun
case bluewallet
case walletofsatoshi
case zebedee
case zeusln
case lnlink
case phoenix
case breez
case bitcoinbeach
case blixtwallet
case river
var model: Model {
switch self {
case .system_default_wallet:
return .init(index: -1, tag: "systemdefaultwallet", displayName: NSLocalizedString("Local default", comment: "Dropdown option label for system default for Lightning wallet."),
link: "lightning:", appStoreLink: "lightning:", image: "")
case .strike:
return .init(index: 0, tag: "strike", displayName: NSLocalizedString("Strike", comment: "Dropdown option label for Lightning wallet, Strike."), link: "strike:",
appStoreLink: "https://apps.apple.com/us/app/strike-bitcoin-payments/id1488724463", image: "strike")
case .cashapp:
return .init(index: 1, tag: "cashapp", displayName: NSLocalizedString("Cash App", comment: "Dropdown option label for Lightning wallet, Cash App."), link: "squarecash://",
appStoreLink: "https://apps.apple.com/us/app/cash-app/id711923939", image: "cashapp")
case .muun:
return .init(index: 2, tag: "muun", displayName: NSLocalizedString("Muun", comment: "Dropdown option label for Lightning wallet, Muun."), link: "muun:", appStoreLink: "https://apps.apple.com/us/app/muun-wallet/id1482037683", image: "muun")
case .bluewallet:
return .init(index: 3, tag: "bluewallet", displayName: NSLocalizedString("Blue Wallet", comment: "Dropdown option label for Lightning wallet, Blue Wallet."), link: "bluewallet:lightning:",
appStoreLink: "https://apps.apple.com/us/app/bluewallet-bitcoin-wallet/id1376878040", image: "bluewallet")
case .walletofsatoshi:
return .init(index: 4, tag: "walletofsatoshi", displayName: NSLocalizedString("Wallet Of Satoshi", comment: "Dropdown option label for Lightning wallet, Wallet Of Satoshi."), link: "walletofsatoshi:lightning:",
appStoreLink: "https://apps.apple.com/us/app/wallet-of-satoshi/id1438599608", image: "walletofsatoshi")
case .zebedee:
return .init(index: 5, tag: "zebedee", displayName: NSLocalizedString("Zebedee", comment: "Dropdown option label for Lightning wallet, Zebedee."), link: "zebedee:lightning:",
appStoreLink: "https://apps.apple.com/us/app/zebedee-wallet/id1484394401", image: "zebedee")
case .zeusln:
return .init(index: 6, tag: "zeusln", displayName: NSLocalizedString("Zeus LN", comment: "Dropdown option label for Lightning wallet, Zeus LN."), link: "zeusln:lightning:",
appStoreLink: "https://apps.apple.com/us/app/zeus-ln/id1456038895", image: "zeusln")
case .lnlink:
return .init(index: 7, tag: "lnlink", displayName: NSLocalizedString("LNLink", comment: "Dropdown option label for Lightning wallet, LNLink."), link: "lnlink:lightning:",
appStoreLink: "https://testflight.apple.com/join/aNY4yuuZ", image: "lnlink")
case .phoenix:
return .init(index: 8, tag: "phoenix", displayName: NSLocalizedString("Phoenix", comment: "Dropdown option label for Lightning wallet, Phoenix."), link: "phoenix://",
appStoreLink: "https://apps.apple.com/us/app/phoenix-wallet/id1544097028", image: "phoenix")
case .breez:
return .init(index: 9, tag: "breez", displayName: NSLocalizedString("Breez", comment: "Dropdown option label for Lightning wallet, Breez."), link: "breez:",
appStoreLink: "https://apps.apple.com/us/app/breez-lightning-client-pos/id1463604142", image: "breez")
case .bitcoinbeach:
return .init(index: 10, tag: "bitcoinbeach", displayName: NSLocalizedString("Bitcoin Beach", comment: "Dropdown option label for Lightning wallet, Bitcoin Beach."), link: "bitcoinbeach://",
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")
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")
}
}
static var allModels: [Model] {
return Self.allCases.map { $0.model }
}
}

View File

@@ -448,7 +448,7 @@ func hex_encode(_ data: Data) -> String {
func random_bytes(count: Int) -> Data {
var data = Data(count: count)
_ = data.withUnsafeMutableBytes { mutableBytes in
SecRandomCopyBytes(kSecRandomDefault, count, mutableBytes.baseAddress!)
SecRandomCopyBytes(kSecRandomDefault, count, mutableBytes)
}
return data
}
@@ -558,7 +558,7 @@ func make_like_event(pubkey: String, privkey: String, liked: NostrEvent) -> Nost
var tags: [[String]] = liked.tags.filter { tag in tag.count >= 2 && (tag[0] == "e" || tag[0] == "p") }
tags.append(["e", liked.id])
tags.append(["p", liked.pubkey])
let ev = NostrEvent(content: "🤙", pubkey: pubkey, kind: 7, tags: tags)
let ev = NostrEvent(content: "", pubkey: pubkey, kind: 7, tags: tags)
ev.calculate_id()
ev.sign(privkey: privkey)

View File

@@ -24,4 +24,19 @@ public class Constants {
NostrEvent(id: UUID().description, content: "Hello World! This is so cool!", pubkey: "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"),
NostrEvent(id: UUID().description, content: "Bonjour Le Monde", pubkey: "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"),
]
// New url prefixes needed to be added to LSApplicationQueriesSchemes
static let WALLETS = """
[
{"id": 0, "name": "Strike", "link": "strike:", "appStoreLink": "https://apps.apple.com/us/app/strike-bitcoin-payments/id1488724463", "image": "strike"},
{"id": 1, "name": "Cash App", "link": "squarecash://", "appStoreLink": "https://apps.apple.com/us/app/cash-app/id711923939", "image": "cashapp"},
{"id": 2, "name": "Muun", "link": "muun:", "appStoreLink": "https://apps.apple.com/us/app/muun-wallet/id1482037683", "image": "muun"},
{"id": 3, "name": "Blue Wallet", "link": "bluewallet:lightning:", "appStoreLink": "https://apps.apple.com/us/app/bluewallet-bitcoin-wallet/id1376878040", "image": "bluewallet"},
{"id": 4, "name": "Wallet Of Satoshi", "link": "walletofsatoshi:lightning:", "appStoreLink": "https://apps.apple.com/us/app/wallet-of-satoshi/id1438599608", "image": "walletofsatoshi"},
{"id": 5, "name": "Zebedee", "link": "zebedee:lightning:", "appStoreLink": "https://apps.apple.com/us/app/zebedee-wallet/id1484394401", "image": "zebedee"},
{"id": 6, "name": "Zeus LN", "link": "zeusln:lightning:", "appStoreLink": "https://apps.apple.com/us/app/zeus-ln/id1456038895", "image": "zeusln"},
{"id": 7, "name": "LNLink", "link": "lnlink:lightning:", "appStoreLink": "https://testflight.apple.com/join/aNY4yuuZ", "image": "lnlink"},
{"id": 8, "name": "Phoenix", "link": "phoenix://", "appStoreLink": "https://apps.apple.com/us/app/phoenix-wallet/id1544097028", "image": "phoenix"},
]
""".data(using: .utf8)!
}

View File

@@ -1,43 +0,0 @@
//
// Markdown.swift
// damus
//
// Created by Lionello Lunesu on 2022-12-28.
//
import Foundation
public struct Markdown {
private let detector = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
/// Ensure the specified URL has a scheme by prepending "https://" if it's absent.
static func withScheme(_ url: any StringProtocol) -> any StringProtocol {
return url.contains("://") ? url : "https://" + url
}
public static func parse(content: String) -> AttributedString {
// Similar to the parsing in NoteContentView
let md_opts: AttributedString.MarkdownParsingOptions =
.init(interpretedSyntax: .inlineOnlyPreservingWhitespace)
if let txt = try? AttributedString(markdown: content, options: md_opts) {
return txt
} else {
return AttributedString(stringLiteral: content)
}
}
/// Process the input text and add markdown for any embedded URLs.
public func process(_ input: String) -> AttributedString {
let matches = detector.matches(in: input, options: [], range: NSRange(location: 0, length: input.utf16.count))
var output = input
// Start with the last match, because replacing the first would invalidate all subsequent indices
for match in matches.reversed() {
guard let range = Range(match.range, in: input) else { continue }
let url = input[range]
output.replaceSubrange(range, with: "[\(url)](\(Markdown.withScheme(url)))")
}
// TODO: escape unintentional markdown
return Markdown.parse(content: output)
}
}

View File

@@ -7,8 +7,9 @@
import Foundation
public func time_ago_since(_ date: Date, _ calendar: Calendar = Calendar.current) -> String {
public func time_ago_since(_ date: Date) -> String {
let calendar = Calendar.current
let now = Date()
let unitFlags: NSCalendar.Unit = [.second, .minute, .hour, .day, .weekOfMonth, .month, .year]

View File

@@ -58,7 +58,6 @@ struct AddRelayView: View {
Button("Add") {
show_add_relay = false
action(relay)
relay = ""
}
.buttonStyle(.borderedProminent)
.contentShape(Rectangle())

View File

@@ -17,8 +17,8 @@ struct ConfigView: View {
@State var privkey: String
@State var privkey_copied: Bool = false
@State var pubkey_copied: Bool = false
@State var relays: [RelayDescriptor]
@EnvironmentObject var user_settings: UserSettingsStore
let generator = UIImpactFeedbackGenerator(style: .light)
@@ -93,17 +93,6 @@ struct ConfigView: View {
}
}
Section("Wallet Selector") {
Toggle("Show wallet selector", isOn: $user_settings.show_wallet_selector).toggleStyle(.switch)
Picker("Select default wallet",
selection: $user_settings.default_wallet) {
ForEach(Wallet.allCases, id: \.self) { wallet in
Text(wallet.model.displayName)
.tag(wallet.model.tag)
}
}
}
Section("Reset") {
Button("Logout") {
confirm_logout = true

View File

@@ -40,26 +40,26 @@ struct CreateAccountView: View {
}
VStack {
SignupForm {
FormLabel(NSLocalizedString("Username", comment: "Label to prompt username entry."))
FormLabel("Username")
HStack(spacing: 0.0) {
Text("@")
.foregroundColor(.white)
.padding(.leading, -25.0)
FormTextInput(NSLocalizedString("satoshi", comment: "Example username of Bitcoin creator(s), Satoshi Nakamoto."), text: $account.nick_name)
FormTextInput("satoshi", text: $account.nick_name)
.autocorrectionDisabled(true)
.textInputAutocapitalization(.never)
}
FormLabel(NSLocalizedString("Display Name", comment: "Label to prompt display name entry."), optional: true)
FormTextInput(NSLocalizedString("Satoshi Nakamoto", comment: "Name of Bitcoin creator(s)."), text: $account.real_name)
FormLabel("Display Name", optional: true)
FormTextInput("Satoshi Nakamoto", text: $account.real_name)
.textInputAutocapitalization(.words)
FormLabel(NSLocalizedString("About", comment: "Label to prompt for about text entry for user to describe about themself."), optional: true)
FormTextInput(NSLocalizedString("Creator(s) of Bitcoin. Absolute legend.", comment: "Example description about Bitcoin creator(s), Satoshi Nakamoto."), text: $account.about)
FormLabel("About", optional: true)
FormTextInput("Creator(s) of Bitcoin. Absolute legend.", text: $account.about)
FormLabel(NSLocalizedString("Account ID", comment: "Label to indicate the public ID of the account."))
FormLabel("Account ID")
.onTapGesture {
regen_key()
}
@@ -75,7 +75,7 @@ struct CreateAccountView: View {
NavigationLink(destination: SaveKeysView(account: account), isActive: $is_done) {
EmptyView()
}
DamusWhiteButton(NSLocalizedString("Create", comment: "Button to create account.")) {
DamusWhiteButton("Create") {
self.is_done = true
}
.padding()

View File

@@ -9,19 +9,10 @@ import SwiftUI
struct DirectMessagesView: View {
let damus_state: DamusState
@State var open_dm: Bool = false
@State var pubkey: String = ""
@State var active_model: DirectMessageModel = DirectMessageModel()
@EnvironmentObject var model: DirectMessagesModel
var MainContent: some View {
ScrollView {
let chat = DMChatView(damus_state: damus_state, pubkey: pubkey)
.environmentObject(active_model)
NavigationLink(destination: chat, isActive: $open_dm) {
EmptyView()
}
LazyVStack {
if model.dms.isEmpty, !model.loading {
EmptyTimelineView()
@@ -39,12 +30,12 @@ struct DirectMessagesView: View {
func MaybeEvent(_ tup: (String, DirectMessageModel)) -> some View {
Group {
if let ev = tup.1.events.last {
let chat = DMChatView(damus_state: damus_state, pubkey: tup.0)
.environmentObject(tup.1)
NavigationLink(destination: chat) {
EventView(damus: damus_state, event: ev, pubkey: tup.0, show_friend_icon: true)
.onTapGesture {
pubkey = tup.0
active_model = tup.1
open_dm = true
}
.buttonStyle(PlainButtonStyle())
} else {
EmptyView()
}

View File

@@ -142,7 +142,7 @@ struct EditMetadataView: View {
}
Section("About Me") {
let placeholder = NSLocalizedString("Absolute Boss", comment: "Placeholder text for About Me description.")
let placeholder = "Absolute Boss"
ZStack(alignment: .topLeading) {
TextEditor(text: $about)
.textInputAutocapitalization(.sentences)
@@ -169,9 +169,9 @@ struct EditMetadataView: View {
Text("NIP-05 Verification")
}, footer: {
if let parts = nip05_parts {
Text(String.localizedStringWithFormat("'%@' at '%@' will be used for verification", parts.username, parts.host))
Text("'\(parts.username)' at '\(parts.host)' will be used for verification")
} else {
Text(String.localizedStringWithFormat("'%@' is an invalid nip05 identifier. It should look like an email.", nip05))
Text("'\(nip05)' is an invalid nip05 identifier. It should look like an email.")
}
})

View File

@@ -59,9 +59,9 @@ struct EventActionBar: View {
HStack(alignment: .bottom) {
Text("\(bar.likes > 0 ? "\(bar.likes)" : "")")
.font(.footnote.weight(.medium))
.foregroundColor(bar.liked ? Color.orange : Color.gray)
.foregroundColor(bar.liked ? Color.red : Color.gray)
LikeButton(liked: bar.liked) {
EventActionButton(img: bar.liked ? "heart.fill" : "heart", col: bar.liked ? Color.red : nil) {
if bar.liked {
notify(.delete, bar.our_like)
} else {
@@ -145,25 +145,6 @@ func EventActionButton(img: String, col: Color?, action: @escaping () -> ()) ->
.padding(.trailing, 40)
}
struct LikeButton: View {
let liked: Bool
let action: () -> ()
@Environment(\.colorScheme) var colorScheme
var body: some View {
Button(action: action) {
if liked {
Text("🤙")
} else {
Label("&nbsp;", systemImage: "hand.thumbsup")
.font(.footnote.weight(.medium))
.foregroundColor(Color.gray)
}
}
}
}
struct EventActionBar_Previews: PreviewProvider {
static var previews: some View {

View File

@@ -401,7 +401,7 @@ func reply_desc(profiles: Profiles, event: NostrEvent) -> String {
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.")
return "Reply to self"
}
let names: [String] = pubkeys.map {
@@ -411,14 +411,20 @@ func reply_desc(profiles: Profiles, event: NostrEvent) -> String {
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)
let and_other = reply_others_desc(n: n, n_pubkeys: pubkeys.count)
return "Replying to \(names[0]), \(names[1])\(and_other)"
}
return String.localizedStringWithFormat("Replying to %@ & %@", names[0], names[1])
return "Replying to \(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)
let and_other = reply_others_desc(n: n, n_pubkeys: pubkeys.count)
return "Replying to \(names[0])\(and_other)"
}
func reply_others_desc(n: Int, n_pubkeys: Int) -> String {
let other = n - n_pubkeys
let plural = other == 1 ? "" : "s"
return n > 1 ? " & \(other) other\(plural)" : ""
}

View File

@@ -11,8 +11,6 @@ struct FollowUserView: View {
let target: FollowTarget
let damus_state: DamusState
static let markdown = Markdown()
var body: some View {
HStack {
let pmodel = ProfileModel(pubkey: target.pubkey, damus: damus_state)
@@ -25,8 +23,8 @@ struct FollowUserView: View {
VStack(alignment: .leading) {
let profile = damus_state.profiles.lookup(id: target.pubkey)
ProfileName(pubkey: target.pubkey, profile: profile, contacts: damus_state.contacts, show_friend_confirmed: false)
if let about = profile?.about {
Text(FollowUserView.markdown.process(about))
if let about = profile.flatMap { $0.about } {
Text(about)
.lineLimit(3)
.font(.footnote)
}

View File

@@ -70,10 +70,17 @@ struct NoteContentView: View {
let size: EventViewKind
func MainContent() -> some View {
return VStack(alignment: .leading) {
Text(Markdown.parse(content: artifacts.content))
.font(eventviewsize_to_font(size))
let md_opts: AttributedString.MarkdownParsingOptions =
.init(interpretedSyntax: .inlineOnlyPreservingWhitespace)
return VStack(alignment: .leading) {
if let txt = try? AttributedString(markdown: artifacts.content, options: md_opts) {
Text(txt)
.font(eventviewsize_to_font(size))
} else {
Text(artifacts.content)
.font(eventviewsize_to_font(size))
}
if show_images && artifacts.images.count > 0 {
ImageCarousel(urls: artifacts.images)
} else if !show_images && artifacts.images.count > 0 {

View File

@@ -12,7 +12,7 @@ enum NostrPostResult {
case cancel
}
let POST_PLACEHOLDER = NSLocalizedString("Type your post here...", comment: "Text box prompt to ask user to type their post.")
let POST_PLACEHOLDER = "Type your post here..."
struct PostView: View {
@State var post: String = ""

View File

@@ -33,6 +33,8 @@ func pfp_line_width(_ h: Highlight) -> CGFloat {
}
struct InnerProfilePicView: View {
@Environment(\.redactionReasons) private var reasons
let url: URL?
let pubkey: String
let size: CGFloat
@@ -52,6 +54,7 @@ struct InnerProfilePicView: View {
var body: some View {
Group {
if reasons.isEmpty {
KFAnimatedImage(url)
.configure { view in
view.framePreloadCount = 1
@@ -63,6 +66,9 @@ struct InnerProfilePicView: View {
.scaleFactor(UIScreen.main.scale)
.loadDiskFileSynchronously()
.fade(duration: 0.1)
} else {
KFImage(url)
}
}
.frame(width: size, height: size)
.clipShape(Circle())

View File

@@ -22,13 +22,13 @@ enum FollowState {
func follow_btn_txt(_ fs: FollowState) -> String {
switch fs {
case .follows:
return NSLocalizedString("Unfollow", comment: "Button to unfollow a user.")
return "Unfollow"
case .following:
return NSLocalizedString("Following...", comment: "Label to indicate that the user is in the process of following another user.")
return "Following..."
case .unfollowing:
return NSLocalizedString("Unfollowing...", comment: "Label to indicate that the user is in the process of unfollowing another user.")
return "Unfollowing..."
case .unfollows:
return NSLocalizedString("Follow", comment: "Button to follow a user.")
return "Follow"
}
}
@@ -119,22 +119,23 @@ struct ProfileView: View {
@StateObject var profile: ProfileModel
@StateObject var followers: FollowersModel
@State private var showingEditProfile = false
@State var showing_select_wallet: Bool = false
@State var showingSelectWallet: Bool = false
@State var inv: String = ""
@State var is_zoomed: Bool = false
@StateObject var user_settings = UserSettingsStore()
@Environment(\.dismiss) var dismiss
@Environment(\.colorScheme) var colorScheme
//@EnvironmentObject var profile: ProfileModel
func LNButton(lnurl: String, profile: Profile) -> some View {
func LNButton(lud06: String?, lud16: String?, profile: Profile) -> some View {
Button(action: {
if user_settings.show_wallet_selector {
showing_select_wallet = true
if let l = lud06 {
inv = l
} else {
open_with_wallet(wallet: user_settings.default_wallet.model, invoice: lnurl)
inv = lud16 ?? ""
}
showingSelectWallet = true
}) {
Image(systemName: "bolt.circle")
.symbolRenderingMode(.palette)
@@ -147,14 +148,11 @@ struct ProfileView: View {
Label("Copy LNURL", systemImage: "doc.on.doc")
}
}
}.sheet(isPresented: $showing_select_wallet, onDismiss: {showing_select_wallet = false}) {
SelectWalletView(showingSelectWallet: $showing_select_wallet, invoice: lnurl)
.environmentObject(user_settings)
}.sheet(isPresented: $showingSelectWallet, onDismiss: {showingSelectWallet = false}) {
SelectWalletView(showingSelectWallet: $showingSelectWallet, invoice: $inv)
}
}
static let markdown = Markdown()
var DMButton: some View {
let dm_model = damus_state.dms.lookup_or_create(profile.pubkey)
let dmview = DMChatView(damus_state: damus_state, pubkey: profile.pubkey)
@@ -183,13 +181,14 @@ struct ProfileView: View {
Spacer()
if let profile = data {
if let lnurl = profile.lnurl {
LNButton(lnurl: lnurl, profile: profile)
if (profile.lud06 != nil || profile.lud16 != nil) {
LNButton(lud06: profile.lud06, lud16: profile.lud16, profile: profile)
}
}
DMButton
if profile.pubkey != damus_state.pubkey {
FollowButtonView(
target: profile.get_follow_target(),
@@ -206,7 +205,7 @@ struct ProfileView: View {
ProfileNameView(pubkey: profile.pubkey, profile: data, contacts: damus_state.contacts)
.padding(.bottom)
Text(ProfileView.markdown.process(data?.about ?? ""))
Text(data?.about ?? "")
.font(.subheadline)
Divider()

View File

@@ -48,22 +48,12 @@ struct RelayView: View {
}
}
.contextMenu {
CopyAction(relay: relay)
if let privkey = state.keypair.privkey {
RemoveAction(privkey: privkey)
}
}
}
func CopyAction(relay: String) -> some View {
Button {
UIPasteboard.general.setValue(relay, forPasteboardType: "public.plain-text")
} label: {
Label("Copy", systemImage: "doc.on.doc")
}
}
func RemoveAction(privkey: String) -> some View {
Button {
guard let ev = state.contacts.event else {
@@ -82,6 +72,11 @@ struct RelayView: View {
}
.tint(.red)
}
}
fileprivate func remove_action() {
}
struct RelayView_Previews: PreviewProvider {

View File

@@ -67,7 +67,7 @@ struct SaveKeysView: View {
complete_account_creation(account)
}
} else {
DamusWhiteButton(NSLocalizedString("Let's go!", comment: "Button to complete account creation and start using the app.")) {
DamusWhiteButton("Let's go!") {
complete_account_creation(account)
}
}
@@ -147,9 +147,6 @@ struct SaveKeyView: View {
var body: some View {
HStack {
Spacer()
VStack {
spacerBlock(width: 0, height: 0)
Button(action: copy_text) {
Label("", systemImage: is_copied ? "checkmark.circle.fill" : "doc.on.doc")
.foregroundColor(is_copied ? .green : .white)
@@ -165,7 +162,6 @@ struct SaveKeyView: View {
}
}
}
}
Text(text)
.padding(5)
@@ -178,15 +174,8 @@ struct SaveKeyView: View {
.onTapGesture {
copy_text()
}
spacerBlock(width: 0, height: 0) /// set a 'width' > 0 here to vary key Text's aspect ratio
}
}
@ViewBuilder private func spacerBlock(width: CGFloat, height: CGFloat) -> some View {
Color.orange.opacity(1)
.frame(width: width, height: height)
}
}
struct SaveKeysView_Previews: PreviewProvider {

View File

@@ -55,7 +55,7 @@ struct SearchHomeView: View {
// Fetch new information by unsubscribing and resubscribing to the relay
model.unsubscribe()
model.subscribe()
}.padding(.horizontal)
}
}
var MainContent: some View {

View File

@@ -7,16 +7,24 @@
import SwiftUI
struct WalletItem : Decodable, Identifiable, Hashable {
var id: Int
var name : String
var link : String
var appStoreLink : String
var image: String
}
struct SelectWalletView: View {
@Binding var showingSelectWallet: Bool
let invoice: String
@Binding var invoice: String
@Environment(\.openURL) private var openURL
@State var invoice_copied: Bool = false
@EnvironmentObject var user_settings: UserSettingsStore
@State var allWalletModels: [Wallet.Model] = Wallet.allModels
let generator = UIImpactFeedbackGenerator(style: .light)
let walletItems = try! JSONDecoder().decode([WalletItem].self, from: Constants.WALLETS)
var body: some View {
NavigationView {
Form {
@@ -38,25 +46,31 @@ struct SelectWalletView: View {
Section("Select a lightning wallet"){
List{
Button() {
let wallet_model = user_settings.default_wallet.model
open_with_wallet(wallet: wallet_model, invoice: invoice)
if let url = URL(string: "lightning:\(invoice)"), UIApplication.shared.canOpenURL(url) {
openURL(url)
}
} label: {
HStack {
Text("Default Wallet").font(.body).foregroundColor(.blue)
}
}.buttonStyle(.plain)
List($allWalletModels) { $wallet in
if wallet.index >= 0 {
ForEach(walletItems, id: \.self) { wallet in
Button() {
open_with_wallet(wallet: wallet, invoice: invoice)
if let url = URL(string: "\(wallet.link)\(invoice)"), UIApplication.shared.canOpenURL(url) {
print("opening wallet url \(url)")
openURL(url)
} else {
if let url = URL(string: wallet.appStoreLink), UIApplication.shared.canOpenURL(url) {
openURL(url)
}
}
} label: {
HStack {
Image(wallet.image).resizable().frame(width: 32.0, height: 32.0,alignment: .center).cornerRadius(5)
Text(wallet.displayName).font(.body)
Text(wallet.name).font(.body)
}
}.buttonStyle(.plain)
}
}
}.padding(.vertical, 2.5)
}
}.navigationBarTitle(Text("Pay the lightning invoice"), displayMode: .inline).navigationBarItems(trailing: Button(action: {
@@ -73,6 +87,6 @@ struct SelectWalletView_Previews: PreviewProvider {
@State static var invoice: String = ""
static var previews: some View {
SelectWalletView(showingSelectWallet: $show, invoice: "")
SelectWalletView(showingSelectWallet: $show, invoice: $invoice)
}
}

View File

@@ -60,7 +60,7 @@ struct SetupView: View {
CarouselView()
DamusWhiteButton(NSLocalizedString("Create Account", comment: "Button to create an account.")) {
DamusWhiteButton("Create Account") {
self.state = .create_account
}

View File

@@ -84,12 +84,22 @@ struct BuildThreadV2View: View {
return sub_id
}
func handle_current_events(ev: NostrEvent) {
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 == current_events_uuid {
if current_event != nil {
return
}
current_event = ev
current_event = nostr_event
thread = ThreadV2(
parentEvents: [],
@@ -126,10 +136,11 @@ struct BuildThreadV2View: View {
)
childs_events_uuid = subscribe(filters: [childs_events])
print("ThreadV2View: Ask for children (\(childs_events) (\(childs_events_uuid))")
return
}
func handle_parent_events(sub_id: String, nostr_event: NostrEvent) {
if parents_events_uuids.contains(id) {
// We are filtering this later
thread!.parentEvents.append(nostr_event)
@@ -159,28 +170,7 @@ struct BuildThreadV2View: View {
}
thread!.clean()
unsubscribe(sub_id)
return
}
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 == current_events_uuid {
handle_current_events(ev: nostr_event)
return
}
if parents_events_uuids.contains(id) {
handle_parent_events(sub_id: id, nostr_event: nostr_event)
unsubscribe(id)
return
}
@@ -297,8 +287,8 @@ struct ThreadV2View: View {
)
}.buttonStyle(.plain)
}
}.padding()
}.navigationBarTitle("Thread")
}
}.padding().navigationBarTitle("Thread")
}
}
}

View File

@@ -1,4 +0,0 @@
/* Bundle display name */
"CFBundleDisplayName" = "Damus";
/* Bundle name */
"CFBundleName" = "damus";

Binary file not shown.

View File

@@ -1,42 +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> &amp; 1 other</string>
<key>other</key>
<string> &amp; %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> &amp; 1 other</string>
<key>other</key>
<string> &amp; %d others</string>
</dict>
</dict>
</dict>
</plist>

View File

@@ -1,4 +0,0 @@
/* Bundle display name */
"CFBundleDisplayName" = "Damus";
/* Bundle name */
"CFBundleName" = "damus";

Binary file not shown.

View File

@@ -1,42 +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> &amp; 1 other</string>
<key>other</key>
<string> &amp; %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> &amp; 1 other</string>
<key>other</key>
<string> &amp; %d others</string>
</dict>
</dict>
</dict>
</plist>

View File

@@ -1,4 +0,0 @@
/* Bundle display name */
"CFBundleDisplayName" = "Damus";
/* Bundle name */
"CFBundleName" = "damus";

Binary file not shown.

View File

@@ -1,42 +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> &amp; 1 other</string>
<key>other</key>
<string> &amp; %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> &amp; 1 other</string>
<key>other</key>
<string> &amp; %d others</string>
</dict>
</dict>
</dict>
</plist>

View File

@@ -18,40 +18,6 @@ final class InvoiceTests: XCTestCase {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
func testParseAnyAmountInvoice() throws {
let invstr = "LNBC1P3MR5UJSP5G7SA48YD4JWTTPCHWMY4QYN4UWZQCJQ8NMWKD6QE3HCRVYTDLH9SPP57YM9TSA9NN4M4XU59XMJCXKR7YDV29DDP6LVQUT46ZW6CU3KE9GQDQ9V9H8JXQ8P3MYLZJCQPJRZJQF60PZDVNGGQWQDNERZSQN35L8CVQ3QG2Z5NSZYD0D3Q0JW2TL6VUZA7FYQQWKGQQYQQQQLGQQQQXJQQ9Q9QXPQYSGQ39EM4QJMQFKZGJXZVGL7QJMYNSWA8PGDTAGXXRG5Z92M7VLCGKQK2L2THDF8LM0AUKAURH7FVAWDLRNMVF38W4EYJDNVN9V4Z9CRS5CQCV465C"
let parsed = parse_mentions(content: invstr, tags: [])
XCTAssertNotNil(parsed)
XCTAssertEqual(parsed.count, 1)
XCTAssertNotNil(parsed[0].is_invoice)
guard let invoice = parsed[0].is_invoice else {
return
}
XCTAssertEqual(invoice.amount, .any)
//XCTAssertEqual(invoice.expiry, 604800)
//XCTAssertEqual(invoice.created_at, 1666139119)
XCTAssertEqual(invoice.string, invstr)
}
func testTextAfterInvoice() throws {
let invstr = """
LNBC1P3MR5UJSP5G7SA48YD4JWTTPCHWMY4QYN4UWZQCJQ8NMWKD6QE3HCRVYTDLH9SPP57YM9TSA9NN4M4XU59XMJCXKR7YDV29DDP6LVQUT46ZW6CU3KE9GQDQ9V9H8JXQ8P3MYLZJCQPJRZJQF60PZDVNGGQWQDNERZSQN35L8CVQ3QG2Z5NSZYD0D3Q0JW2TL6VUZA7FYQQWKGQQYQQQQLGQQQQXJQQ9Q9QXPQYSGQ39EM4QJMQFKZGJXZVGL7QJMYNSWA8PGDTAGXXRG5Z92M7VLCGKQK2L2THDF8LM0AUKAURH7FVAWDLRNMVF38W4EYJDNVN9V4Z9CRS5CQCV465C hi there
"""
let parsed = parse_mentions(content: invstr, tags: [])
XCTAssertNotNil(parsed)
XCTAssertEqual(parsed.count, 2)
XCTAssertNotNil(parsed[0].is_invoice)
XCTAssertEqual(parsed[1].is_text, " hi there")
guard let invoice = parsed[0].is_invoice else {
return
}
XCTAssertEqual(invoice.amount, .any)
//XCTAssertEqual(invoice.expiry, 604800)
//XCTAssertEqual(invoice.created_at, 1666139119)
}
func testParseInvoiceUpper() throws {
let invstr = "LNBC100N1P357SL0SP5T9N56WDZTUN39LGDQLR30XQWKSG3K69Q4Q2RKR52APLUJW0ESN0QPP5MRQGLJK62Z20Q4NVGR6LZCYN6FHYLZCCWDVU4K77APG3ZMRKUJJQDPZW35XJUEQD9EJQCFQV3JHXCMJD9C8G6T0DCXQYJW5QCQPJRZJQT56H4GVP5YX36U2UZQA6QWCSK3E2DUUNFXPPZJ9VHYPC3WFE2WSWZ607UQQ3XQQQSQQQQQQQQQQQLQQYG9QYYSGQAGX5H20AEULJ3GDWX3KXS8U9F4MCAKDKWUAKASAMM9562FFYR9EN8YG20LG0YGNR9ZPWP68524KMDA0T5XP2WYTEX35PU8HAPYJAJXQPSQL29R"
let parsed = parse_mentions(content: invstr, tags: [])
@@ -62,7 +28,7 @@ LNBC1P3MR5UJSP5G7SA48YD4JWTTPCHWMY4QYN4UWZQCJQ8NMWKD6QE3HCRVYTDLH9SPP57YM9TSA9NN
guard let invoice = parsed[0].is_invoice else {
return
}
XCTAssertEqual(invoice.amount, .specific(10000))
XCTAssertEqual(invoice.amount, 10000)
XCTAssertEqual(invoice.expiry, 604800)
XCTAssertEqual(invoice.created_at, 1666139119)
XCTAssertEqual(invoice.string, invstr)
@@ -96,7 +62,7 @@ LNBC1P3MR5UJSP5G7SA48YD4JWTTPCHWMY4QYN4UWZQCJQ8NMWKD6QE3HCRVYTDLH9SPP57YM9TSA9NN
guard let invoice = parsed[0].is_invoice else {
return
}
XCTAssertEqual(invoice.amount, .specific(10000))
XCTAssertEqual(invoice.amount, 10000)
XCTAssertEqual(invoice.expiry, 604800)
XCTAssertEqual(invoice.created_at, 1666139119)
XCTAssertEqual(invoice.string, invstr)

View File

@@ -1,43 +0,0 @@
//
// MarkdownTests.swift
// damusTests
//
// Created by Lionello Lunesu on 2022-12-28.
//
import XCTest
@testable import damus
class MarkdownTests: XCTestCase {
let md_opts: AttributedString.MarkdownParsingOptions =
.init(interpretedSyntax: .inlineOnlyPreservingWhitespace)
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.
}
func test_convert_link() throws {
let helper = Markdown()
let md = helper.process("prologue https://nostr.build epilogue")
let expected = try AttributedString(markdown: "prologue [https://nostr.build](https://nostr.build) epilogue", options: md_opts)
XCTAssertEqual(md, expected)
}
func test_convert_link_no_scheme() throws {
let helper = Markdown()
let md = helper.process("prologue damus.io epilogue")
let expected = try AttributedString(markdown: "prologue [damus.io](https://damus.io) epilogue", options: md_opts)
XCTAssertEqual(md, expected)
}
func test_convert_links() throws {
let helper = Markdown()
let md = helper.process("prologue damus.io https://nostr.build epilogue")
let expected = try AttributedString(markdown: "prologue [damus.io](https://damus.io) [https://nostr.build](https://nostr.build) epilogue", options: md_opts)
XCTAssertEqual(md, expected)
}
}

View File

@@ -11,27 +11,24 @@ import XCTest
final class TimeAgoTests: XCTestCase {
func testTimeAgoSince() {
let locale = Locale(identifier: "en_US")
let calendar = locale.calendar
XCTAssertEqual(time_ago_since(Date.now, calendar), "now")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-2), calendar), "now")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-3), calendar), "3s")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-59), calendar), "59s")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-60), calendar), "1min")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-3599), calendar), "59min")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-3600), calendar), "1h")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-86399), calendar), "23h")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-86400), calendar), "1d")
XCTAssertEqual(time_ago_since(calendar.date(byAdding: .weekOfMonth, value: -1, to: Date.now)!.addingTimeInterval(1), calendar), "6d")
XCTAssertEqual(time_ago_since(calendar.date(byAdding: .weekOfMonth, value: -1, to: Date.now)!, calendar), "1w")
XCTAssertEqual(time_ago_since(calendar.date(byAdding: .weekOfMonth, value: -2, to: Date.now)!, calendar), "2w")
XCTAssertEqual(time_ago_since(calendar.date(byAdding: .weekOfMonth, value: -3, to: Date.now)!, calendar), "3w")
XCTAssertEqual(time_ago_since(Date.now), "now")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-2)), "now")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-3)), "3s")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-59)), "59s")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-60)), "1m")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-3599)), "59m")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-3600)), "1h")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-86399)), "23h")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-86400)), "1d")
XCTAssertEqual(time_ago_since(Calendar.current.date(byAdding: .weekOfMonth, value: -1, to: Date.now)!.addingTimeInterval(1)), "6d")
XCTAssertEqual(time_ago_since(Calendar.current.date(byAdding: .weekOfMonth, value: -1, to: Date.now)!), "1w")
XCTAssertEqual(time_ago_since(Calendar.current.date(byAdding: .weekOfMonth, value: -2, to: Date.now)!), "2w")
XCTAssertEqual(time_ago_since(Calendar.current.date(byAdding: .weekOfMonth, value: -3, to: Date.now)!), "3w")
// Not testing the 4-5 week boundary since how it is formatted depends on which month and year it is currently when this test executes.
XCTAssertEqual(time_ago_since(calendar.date(byAdding: .month, value: -1, to: Date.now)!, calendar), "1mo")
XCTAssertEqual(time_ago_since(calendar.date(byAdding: .year, value: -1, to: Date.now)!.addingTimeInterval(1), calendar), "11mo")
XCTAssertEqual(time_ago_since(calendar.date(byAdding: .year, value: -1, to: Date.now)!, calendar), "1y")
XCTAssertEqual(time_ago_since(calendar.date(byAdding: .year, value: -1000, to: Date.now)!, calendar), "1,000y")
XCTAssertEqual(time_ago_since(Calendar.current.date(byAdding: .month, value: -1, to: Date.now)!), "1mo")
XCTAssertEqual(time_ago_since(Calendar.current.date(byAdding: .year, value: -1, to: Date.now)!.addingTimeInterval(1)), "11mo")
XCTAssertEqual(time_ago_since(Calendar.current.date(byAdding: .year, value: -1, to: Date.now)!), "1y")
XCTAssertEqual(time_ago_since(Calendar.current.date(byAdding: .year, value: -1000, to: Date.now)!), "1,000y")
}
}

View File

@@ -33,13 +33,6 @@ class damusTests: XCTestCase {
}
}
func testRandomBytes() {
let bytes = random_bytes(count: 32)
print("testRandomBytes \(hex_encode(bytes))")
XCTAssertEqual(bytes.count, 32)
}
func testParseMentionWithMarkdown() {
let md = """
Testing markdown in damus

View File

@@ -1,22 +0,0 @@
git:
filters:
- filter_type: file
file_format: STRINGS
source_language: en
source_file: damus Localizations/en.xcloc/Source Contents/damus/en.lproj/InfoPlist.strings
translation_files_expression: damus/<lang>.lproj/InfoPlist.strings
- filter_type: file
file_format: STRINGS
source_language: en
source_file: damus Localizations/en.xcloc/Source Contents/damus/en.lproj/Localizable.strings
translation_files_expression: damus/<lang>.lproj/Localizable.strings
- filter_type: file
file_format: STRINGSDICT
source_language: en
source_file: damus Localizations/en.xcloc/Source Contents/damus/en.lproj/Localizable.stringsdict
translation_files_expression: damus/<lang>.lproj/Localizable.stringsdict
settings:
pr_branch_name: tx_translations_<br_unique_id>