Compare commits

..

1 Commits

Author SHA1 Message Date
8f6ea4d8dd Add support for scanning nprofile QR codes
Changelog-Added: Added support for scanning nprofile QR codes

Closes: https://github.com/damus-io/damus/issues/2671
Signed-off-by: Terry Yiu <git@tyiu.xyz>
2025-08-18 08:36:58 -07:00
25 changed files with 62 additions and 280 deletions

View File

@@ -33,10 +33,6 @@
3A515C542DF5371D002D3B34 /* TrustedNetworkButtonTipViewStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A515C532DF5371D002D3B34 /* TrustedNetworkButtonTipViewStyle.swift */; };
3A515C552DF5371D002D3B34 /* TrustedNetworkButtonTipViewStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A515C532DF5371D002D3B34 /* TrustedNetworkButtonTipViewStyle.swift */; };
3A515C562DF5371D002D3B34 /* TrustedNetworkButtonTipViewStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A515C532DF5371D002D3B34 /* TrustedNetworkButtonTipViewStyle.swift */; };
3A7379D42E5D5C4A00DF8B4E /* DSWaveformImageViews in Frameworks */ = {isa = PBXBuildFile; productRef = 3A7379D32E5D5C4A00DF8B4E /* DSWaveformImageViews */; };
3A7379D72E5D5E1900DF8B4E /* DamusAudioPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A7379D62E5D5E1900DF8B4E /* DamusAudioPlayerView.swift */; };
3A7379D82E5D5E1900DF8B4E /* DamusAudioPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A7379D62E5D5E1900DF8B4E /* DamusAudioPlayerView.swift */; };
3A7379D92E5D5E1900DF8B4E /* DamusAudioPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A7379D62E5D5E1900DF8B4E /* DamusAudioPlayerView.swift */; };
3A8CC6CC2A2CFEF900940F5F /* StringUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A8CC6CB2A2CFEF900940F5F /* StringUtil.swift */; };
3A92C0FE2DE16E9800CEEBAC /* FaviconCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A92C0FD2DE16E9800CEEBAC /* FaviconCache.swift */; };
3A92C0FF2DE16E9800CEEBAC /* FaviconCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A92C0FD2DE16E9800CEEBAC /* FaviconCache.swift */; };
@@ -1927,7 +1923,6 @@
3A66D927299472FA008B44F4 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/InfoPlist.strings; sourceTree = "<group>"; };
3A66D928299472FA008B44F4 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
3A66D929299472FA008B44F4 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ja; path = ja.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
3A7379D62E5D5E1900DF8B4E /* DamusAudioPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusAudioPlayerView.swift; sourceTree = "<group>"; };
3A821C3E29E819D500B4BCA7 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
3A821C3F29E819D500B4BCA7 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = "<group>"; };
3A821C4029E819D500B4BCA7 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = fr; path = fr.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
@@ -2736,7 +2731,6 @@
buildActionMask = 2147483647;
files = (
3ACF94382DA9A52F00971A4E /* FaviconFinder in Frameworks */,
3A7379D42E5D5C4A00DF8B4E /* DSWaveformImageViews in Frameworks */,
4C06670428FC7EC500038D2A /* Kingfisher in Frameworks */,
D7DB1FE42D5A9AC900CF06DA /* CryptoSwift in Frameworks */,
3A0A30BB2C21397A00F8C9BC /* EmojiPicker in Frameworks */,
@@ -2830,14 +2824,6 @@
path = Tips;
sourceTree = "<group>";
};
3A7379D52E5D5DF000DF8B4E /* Audio */ = {
isa = PBXGroup;
children = (
3A7379D62E5D5E1900DF8B4E /* DamusAudioPlayerView.swift */,
);
path = Audio;
sourceTree = "<group>";
};
3AA24800297E3DAE0090C62D /* Reposts */ = {
isa = PBXGroup;
children = (
@@ -4406,7 +4392,6 @@
children = (
5C78A79D2E303D2600CF177D /* Models */,
4CFF8F6129CC9A80008DB934 /* Images */,
3A7379D52E5D5DF000DF8B4E /* Audio */,
4C1A9A2829DDF53B00516EAC /* Video */,
BA3759952ABCCF360018D73B /* Camera */,
4C198DEA29F88C6B004C165C /* BlurHash */,
@@ -5075,7 +5060,6 @@
D7C48C0A2D12DE0C00A3BACF /* SwiftyCrop */,
D7DB1FE32D5A9AC900CF06DA /* CryptoSwift */,
3ACF94372DA9A52F00971A4E /* FaviconFinder */,
3A7379D32E5D5C4A00DF8B4E /* DSWaveformImageViews */,
);
productName = damus;
productReference = 4CE6DEE327F7A08100C66700 /* damus.app */;
@@ -5287,7 +5271,6 @@
D7C48C092D12DE0C00A3BACF /* XCRemoteSwiftPackageReference "SwiftyCrop" */,
D7DB1FE22D5A9AC900CF06DA /* XCRemoteSwiftPackageReference "CryptoSwift" */,
3ACF94362DA9A52F00971A4E /* XCRemoteSwiftPackageReference "FaviconFinder" */,
3A7379D22E5D5C4A00DF8B4E /* XCRemoteSwiftPackageReference "DSWaveformImage" */,
);
productRefGroup = 4CE6DEE427F7A08100C66700 /* Products */;
projectDirPath = "";
@@ -5822,7 +5805,6 @@
E0EE9DD42B8E5FEA00F3002D /* ImageProcessing.swift in Sources */,
4CB883B0297705DD00DC99E7 /* NoteZapButton.swift in Sources */,
D7DF58342DFCF18D00E9AD28 /* SendPaymentView.swift in Sources */,
3A7379D72E5D5E1900DF8B4E /* DamusAudioPlayerView.swift in Sources */,
4C363A922825FCF2006E126D /* ProfileUpdate.swift in Sources */,
4C3BEFDA281DCA1400B3DE84 /* LikeCounter.swift in Sources */,
4C32B9502A9AD44700DC3548 /* FlatBufferBuilder.swift in Sources */,
@@ -6113,7 +6095,6 @@
82D6FB092CD99F7900C925F4 /* SearchHeaderView.swift in Sources */,
82D6FB0A2CD99F7900C925F4 /* DamusGradient.swift in Sources */,
D7DB93052D66A44100DA1EE5 /* Undistractor.swift in Sources */,
3A7379D92E5D5E1900DF8B4E /* DamusAudioPlayerView.swift in Sources */,
82D6FB0C2CD99F7900C925F4 /* GoldSupportGradient.swift in Sources */,
82D6FB0D2CD99F7900C925F4 /* PinkGradient.swift in Sources */,
82D6FB0E2CD99F7900C925F4 /* GrayGradient.swift in Sources */,
@@ -6799,7 +6780,6 @@
D73E5F092C6A97F4007EB227 /* ProfilePicView.swift in Sources */,
D73E5F0A2C6A97F4007EB227 /* ProfileView.swift in Sources */,
D73E5F0B2C6A97F4007EB227 /* ProfileNameView.swift in Sources */,
3A7379D82E5D5E1900DF8B4E /* DamusAudioPlayerView.swift in Sources */,
D73E5F0C2C6A97F4007EB227 /* MaybeAnonPfpView.swift in Sources */,
D73E5F0D2C6A97F4007EB227 /* EventProfileName.swift in Sources */,
D73E5F0E2C6A97F4007EB227 /* FriendIcon.swift in Sources */,
@@ -7942,14 +7922,6 @@
minimumVersion = 0.2.0;
};
};
3A7379D22E5D5C4A00DF8B4E /* XCRemoteSwiftPackageReference "DSWaveformImage" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/dmrschmidt/DSWaveformImage";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 14.2.2;
};
};
3ACF94362DA9A52F00971A4E /* XCRemoteSwiftPackageReference "FaviconFinder" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/will-lumley/FaviconFinder.git";
@@ -8038,11 +8010,6 @@
package = 3A0A30B92C21397A00F8C9BC /* XCRemoteSwiftPackageReference "EmojiPicker" */;
productName = EmojiPicker;
};
3A7379D32E5D5C4A00DF8B4E /* DSWaveformImageViews */ = {
isa = XCSwiftPackageProductDependency;
package = 3A7379D22E5D5C4A00DF8B4E /* XCRemoteSwiftPackageReference "DSWaveformImage" */;
productName = DSWaveformImageViews;
};
3ACF94372DA9A52F00971A4E /* FaviconFinder */ = {
isa = XCSwiftPackageProductDependency;
package = 3ACF94362DA9A52F00971A4E /* XCRemoteSwiftPackageReference "FaviconFinder" */;

View File

@@ -1,5 +1,5 @@
{
"originHash" : "8d71e78d1d7bdc5a85a38932a14f84af755a9e34aeab19f9d540bd11a7b32fbc",
"originHash" : "1fc7e0b44329ba72cd285eeb022b5b92582cd01586b920d243cb0485c2e69dcc",
"pins" : [
{
"identity" : "codescanner",
@@ -17,15 +17,6 @@
"revision" : "e74bbbfbef939224b242ae7c342a90e60b88b5ce"
}
},
{
"identity" : "dswaveformimage",
"kind" : "remoteSourceControl",
"location" : "https://github.com/dmrschmidt/DSWaveformImage",
"state" : {
"revision" : "4c56578ee10128ee2b2c04c9c5aa73812de722db",
"version" : "14.2.2"
}
},
{
"identity" : "emojikit",
"kind" : "remoteSourceControl",

View File

@@ -18,7 +18,6 @@ enum NostrKind: UInt32, Codable {
case boost = 6
case like = 7
case chat = 42
case voice_message = 1222
case mute_list = 10000
case relay_list = 10002
case interest_list = 10015

View File

@@ -62,7 +62,7 @@ class LoadableNostrEventViewModel: ObservableObject {
guard let ev = await self.loadEvent(noteId: note_id) else { return .not_found }
guard let known_kind = ev.known_kind else { return .unknown_or_unsupported_kind }
switch known_kind {
case .text, .highlight, .voice_message:
case .text, .highlight:
return .loaded(route: Route.Thread(thread: ThreadModel(event: ev, damus_state: damus_state)))
case .dm:
let dm_model = damus_state.dms.lookup_or_create(ev.pubkey)

View File

@@ -319,8 +319,6 @@ func classify_url(_ url: URL) -> UrlType {
return .media(.image(url))
case "mp4", "mov", "m3u8":
return .media(.video(url))
case "m4a":
return .media(.audio(url))
default:
return .link(url)
}
@@ -454,8 +452,6 @@ enum UrlType {
return url
case .video(let url):
return url
case .audio(let url):
return url
}
case .link(let url):
return url
@@ -466,7 +462,7 @@ enum UrlType {
switch self {
case .media(let media_url):
switch media_url {
case .image, .audio:
case .image:
return nil
case .video(let url):
return url
@@ -482,28 +478,14 @@ enum UrlType {
switch media_url {
case .image(let url):
return url
case .video, .audio:
case .video:
return nil
}
case .link:
return nil
}
}
var is_audio: URL? {
switch self {
case .media(let media_url):
switch media_url {
case .audio(let url):
return url
case .image, .video:
return nil
}
case .link:
return nil
}
}
var is_link: URL? {
switch self {
case .media:
@@ -526,16 +508,13 @@ enum UrlType {
enum MediaUrl {
case image(URL)
case video(URL)
case audio(URL)
var url: URL {
switch self {
case .image(let url):
return url
case .video(let url):
return url
case .audio(let url):
return url
}
}
}

View File

@@ -253,7 +253,7 @@ struct NoteContentView: View {
Divider()
.frame(height: 1)
switch artifacts.media[index] {
case .image(let url), .video(let url), .audio(let url):
case .image(let url), .video(let url):
Text(abbreviateURL(url))
.font(eventviewsize_to_font(size, font_size: damus_state.settings.font_size))
.foregroundStyle(DamusColors.neutral6)
@@ -477,7 +477,7 @@ struct BlurOverlayView: View {
let damus_state = damus_state
{
switch artifacts.media[0] {
case .image(let url), .video(let url), .audio(let url):
case .image(let url), .video(let url):
Text(abbreviateURL(url, maxLength: 30))
.font(eventviewsize_to_font(size, font_size: damus_state.settings.font_size * 0.8))
.foregroundStyle(.white)

View File

@@ -75,7 +75,7 @@ class ProfileModel: ObservableObject, Equatable {
}
func subscribe() {
var text_filter = NostrFilter(kinds: [.text, .longform, .highlight, .voice_message])
var text_filter = NostrFilter(kinds: [.text, .longform, .highlight])
var profile_filter = NostrFilter(kinds: [.contacts, .metadata, .boost])
var relay_list_filter = NostrFilter(kinds: [.relay_list], authors: [pubkey])
@@ -98,7 +98,7 @@ class ProfileModel: ObservableObject, Equatable {
return
}
let conversation_kinds: [NostrKind] = [.text, .longform, .highlight, .voice_message]
let conversation_kinds: [NostrKind] = [.text, .longform, .highlight]
let limit: UInt32 = 500
let conversations_filter_them = NostrFilter(kinds: conversation_kinds, pubkeys: [damus.pubkey], limit: limit, authors: [pubkey])
let conversations_filter_us = NostrFilter(kinds: conversation_kinds, pubkeys: [pubkey], limit: limit, authors: [damus.pubkey])
@@ -122,7 +122,7 @@ class ProfileModel: ObservableObject, Equatable {
}
private func add_event(_ ev: NostrEvent) {
if ev.is_textlike || ev.known_kind == .boost || ev.known_kind == .voice_message {
if ev.is_textlike || ev.known_kind == .boost {
if self.events.insert(ev) {
self.objectWillChange.send()
}

View File

@@ -123,7 +123,7 @@ struct ProfileView: View {
var filters = ContentFilters.defaults(damus_state: damus_state)
filters.append(fstate.filter)
switch fstate {
case .posts, .posts_and_replies, .follow_list, .voice_messages:
case .posts, .posts_and_replies, .follow_list:
filters.append({ profile.pubkey == $0.pubkey })
case .conversations:
filters.append({ profile.conversation_events.contains($0.id) } )
@@ -438,8 +438,7 @@ struct ProfileView: View {
var tabs: [(String, FilterState)] {
var tabs = [
(NSLocalizedString("Notes", comment: "Label for filter for seeing only notes (instead of notes and replies)."), FilterState.posts),
(NSLocalizedString("Notes & Replies", comment: "Label for filter for seeing notes and replies (instead of only notes)."), FilterState.posts_and_replies),
(NSLocalizedString("Voice", comment: "Label for filter for seeing voice messages."), FilterState.voice_messages)
(NSLocalizedString("Notes & Replies", comment: "Label for filter for seeing notes and replies (instead of only notes)."), FilterState.posts_and_replies)
]
if profile.pubkey != damus_state.pubkey && !profile.conversation_events.isEmpty {
tabs.append((NSLocalizedString("Conversations", comment: "Label for filter for seeing notes and replies that involve conversations between the signed in user and the current profile."), FilterState.conversations))
@@ -470,9 +469,6 @@ struct ProfileView: View {
if filter_state == FilterState.posts_and_replies {
InnerTimelineView(events: profile.events, damus: damus_state, filter: content_filter(FilterState.posts_and_replies))
}
if filter_state == FilterState.voice_messages {
InnerTimelineView(events: profile.events, damus: damus_state, filter: content_filter(FilterState.voice_messages))
}
if filter_state == FilterState.conversations && !profile.conversation_events.isEmpty {
InnerTimelineView(events: profile.events, damus: damus_state, filter: content_filter(FilterState.conversations))
}

View File

@@ -8,7 +8,7 @@
import Foundation
import UIKit
let fallback_zap_amount = 21
let fallback_zap_amount = 1000
let default_emoji_reactions = ["🤣", "🤙", "", "💜", "🔥", "😀", "😃", "😄", "🥶"]
func setting_property_key(key: String) -> String {

View File

@@ -14,7 +14,6 @@ enum FilterState : Int {
case posts_and_replies = 1
case conversations = 2
case follow_list = 3
case voice_messages = 4
func filter(ev: NostrEvent) -> Bool {
switch self {
@@ -26,8 +25,6 @@ enum FilterState : Int {
return true
case .follow_list:
return ev.known_kind == .follow_list
case .voice_messages:
return ev.known_kind == .voice_message
}
}
}

View File

@@ -192,8 +192,6 @@ class HomeModel: ContactsDelegate {
switch kind {
case .chat, .longform, .text, .highlight:
handle_text_event(sub_id: sub_id, ev)
case .voice_message:
handle_voice_message_event(sub_id: sub_id, ev)
case .contacts:
handle_contact_event(sub_id: sub_id, relay_id: relay_id, ev: ev)
case .metadata:
@@ -778,28 +776,7 @@ class HomeModel: ContactsDelegate {
handle_notification(ev: ev)
}
}
func handle_voice_message_event(sub_id: String, _ ev: NostrEvent) {
guard should_show_event(state: damus_state, ev: ev) else {
return
}
// TODO: will we need to process this in other places like zap request contents, etc?
process_image_metadatas(cache: damus_state.events, ev: ev)
damus_state.replies.count_replies(ev, keypair: self.damus_state.keypair)
damus_state.events.insert(ev)
if let quoted_event = ev.referenced_quote_ids.first {
handle_quote_repost_event(ev, target: quoted_event.note_id)
}
if sub_id == home_subid {
insert_home_event(ev)
} else if sub_id == notifications_subid {
handle_notification(ev: ev)
}
}
func got_new_dm(notifs: NewEventsBits, ev: NostrEvent) {
notification_status.new_events = notifs

View File

@@ -8,17 +8,6 @@
import SwiftUI
import Combine
let zapAmounts: [Int: String] = [
69: "😘",
420: "🌿",
5000: "💜",
10_000: "😍",
20_000: "🤩",
50_000: "🔥",
100_000: "🚀",
1_000_000: "🤯",
]
struct ZapAmountItem: Identifiable, Hashable {
let amount: Int
let icon: String
@@ -33,14 +22,19 @@ func get_default_zap_amount_item(_ def: Int) -> ZapAmountItem {
}
func get_zap_amount_items(_ default_zap_amt: Int) -> [ZapAmountItem] {
var entries = zapAmounts.map { ZapAmountItem(amount: $0.key, icon: $0.value) }
// Add default zap amount to the list only if it is not one of the preset entries so that it is not duplicated.
if zapAmounts[default_zap_amt] == nil {
let def_item = get_default_zap_amount_item(default_zap_amt)
entries.append(def_item)
}
let def_item = get_default_zap_amount_item(default_zap_amt)
var entries = [
ZapAmountItem(amount: 69, icon: "😘"),
ZapAmountItem(amount: 420, icon: "🌿"),
ZapAmountItem(amount: 5000, icon: "💜"),
ZapAmountItem(amount: 10_000, icon: "😍"),
ZapAmountItem(amount: 20_000, icon: "🤩"),
ZapAmountItem(amount: 50_000, icon: "🔥"),
ZapAmountItem(amount: 100_000, icon: "🚀"),
ZapAmountItem(amount: 1_000_000, icon: "🤯"),
]
entries.append(def_item)
entries.sort { $0.amount < $1.amount }
return entries
}

View File

@@ -1,44 +0,0 @@
//
// DamusAudioPlayerView.swift
// damus
//
// Created by Terry Yiu on 8/25/25.
//
import DSWaveformImageViews
import SwiftUI
struct DamusAudioPlayerView: View {
let remoteURL: URL
@State var localURL: URL
var body: some View {
GeometryReader { geometry in
WaveformView(audioURL: localURL) { shape in
shape.fill(.white)
shape.fill(.red).mask(alignment: .leading) {
Rectangle().frame(width: geometry.size.width * progress)
}
}
}
Text("Hello, World!")
.task {
URLSession.shared.downloadTask(with: remoteURL) { downloadedURL, urlResponse, error in
guard let downloadedURL = downloadedURL else { return }
let cachesFolderURL = try? FileManager.default.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let audioFileURL = cachesFolderURL!.appendingPathComponent("yourLocalAudioFile.m4a")
try? FileManager.default.copyItem(at: downloadedURL, to: audioFileURL)
DispatchQueue.main.async {
self.localURL = audioFileURL
// self.WaveformView.waveformAudioURL = audioFileURL
}
}
}
}
#Preview {
DamusAudioPlayerView()
}

View File

@@ -57,9 +57,7 @@ struct ImageContainerView: View {
switch url {
case .image(let url):
Img(url: url)
case .audio(let url):
DamusAudioPlayerView()
case .video(let url):
case .video(let url):
DamusVideoPlayerView(url: url, coordinator: video_coordinator, style: .no_controls(on_tap: nil))
}
}

View File

@@ -223,7 +223,7 @@ class CarouselModel: ObservableObject {
private func observe_video_sizes() {
for media_url in urls {
switch media_url {
case .video(let url), .audio(let url):
case .video(let url):
let video_player = damus_state.video.get_player(for: url)
if let video_size = video_player.video_size {
self.media_size_information[url] = video_size // Set the initial size if available
@@ -302,7 +302,6 @@ class CarouselModel: ObservableObject {
struct ImageCarousel<Content: View>: View {
/// The event id of the note that this carousel is displaying
let evid: NoteId
let event: NostrEvent
/// The model that holds information and state of this carousel
/// This is observed to update the view when the model changes
@ObservedObject var model: CarouselModel
@@ -355,8 +354,6 @@ struct ImageCarousel<Content: View>: View {
.onTapGesture {
present(full_screen_item: .full_screen_carousel(urls: model.urls, selectedIndex: $model.selectedIndex))
}
case .audio(let url):
DamusAudioPlayerView()
case .video(let url):
let video_model = model.damus_state.video.get_player(for: url)
DamusVideoPlayerView(

Binary file not shown.

View File

@@ -62,7 +62,6 @@ Sentence composed of 2 variables to describe how many profiles a user is followi
Sentence composed of 2 variables to describe how many quoted reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.
Sentence composed of 2 variables to describe how many reactions there are on a post. In source English, the first variable is the number of reactions, and the second variable is 'Reaction' or 'Reactions'.
Sentence composed of 2 variables to describe how many relay servers a user is connected. In source English, the first variable is the number of relay servers, and the second variable is 'Relay' or 'Relays'.
Sentence composed of 2 variables to describe how many relays a note was found on. In source English, the first variable is the number of relays, and the second variable is 'Relay' or 'Relays'.
Sentence composed of 2 variables to describe how many reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.
Sentence composed of 2 variables to describe how many zap payments there are on a post. In source English, the first variable is the number of zap payments, and the second variable is 'Zap' or 'Zaps'.</note>
</trans-unit>
@@ -646,6 +645,11 @@ Button label giving the user the option to close the sheet from which they were
<note>Button to connect to the relay.
Text for button to conect to Nostr Wallet Connect lightning wallet.</note>
</trans-unit>
<trans-unit id="Connect to Alby Wallet" xml:space="preserve">
<source>Connect to Alby Wallet</source>
<target>Connect to Alby Wallet</target>
<note>Button to attach an Alby Wallet, a service that provides a Lightning wallet for zapping sats. Alby is the name of the service and should not be translated.</note>
</trans-unit>
<trans-unit id="Connect to Coinos" xml:space="preserve">
<source>Connect to Coinos</source>
<target>Connect to Coinos</target>
@@ -2153,11 +2157,6 @@ Section title for deleting the user</note>
<target>Please contact the person who provided the link, and ask for another link.</target>
<note>User-visible tip on what to do if a link contains a deprecated "nrelay" reference.</note>
</trans-unit>
<trans-unit id="Please contact the person who provided the link, and ask for another link. Also, this link may have sensitive information, please use caution before sharing it." xml:space="preserve">
<source>Please contact the person who provided the link, and ask for another link. Also, this link may have sensitive information, please use caution before sharing it.</source>
<target>Please contact the person who provided the link, and ask for another link. Also, this link may have sensitive information, please use caution before sharing it.</target>
<note>User-visible tip on what to do if a link contains an unsupported "nsec" reference.</note>
</trans-unit>
<trans-unit id="Please copy the technical info and send it to our support team." xml:space="preserve">
<source>Please copy the technical info and send it to our support team.</source>
<target>Please copy the technical info and send it to our support team.</target>
@@ -3673,11 +3672,6 @@ User confirm Yes</note>
<target>You opened an invalid link. The link you tried to open refers to "nrelay", which has been deprecated and is not supported.</target>
<note>User-visible error description for a user who tries to open a deprecated "nrelay" link.</note>
</trans-unit>
<trans-unit id="You opened an invalid link. The link you tried to open refers to &quot;nsec&quot;, which is not supported." xml:space="preserve">
<source>You opened an invalid link. The link you tried to open refers to "nsec", which is not supported.</source>
<target>You opened an invalid link. The link you tried to open refers to "nsec", which is not supported.</target>
<note>User-visible error description for a user who tries to open an unsupported "nsec" link.</note>
</trans-unit>
<trans-unit id="You unlocked" xml:space="preserve">
<source>You unlocked</source>
<target>You unlocked</target>
@@ -4598,7 +4592,6 @@ Sentence composed of 2 variables to describe how many profiles a user is followi
Sentence composed of 2 variables to describe how many quoted reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.
Sentence composed of 2 variables to describe how many reactions there are on a post. In source English, the first variable is the number of reactions, and the second variable is 'Reaction' or 'Reactions'.
Sentence composed of 2 variables to describe how many relay servers a user is connected. In source English, the first variable is the number of relay servers, and the second variable is 'Relay' or 'Relays'.
Sentence composed of 2 variables to describe how many relays a note was found on. In source English, the first variable is the number of relays, and the second variable is 'Relay' or 'Relays'.
Sentence composed of 2 variables to describe how many reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.
Sentence composed of 2 variables to describe how many zap payments there are on a post. In source English, the first variable is the number of zap payments, and the second variable is 'Zap' or 'Zaps'.</note>
</trans-unit>
@@ -5185,6 +5178,11 @@ Button label giving the user the option to close the view when no content is ava
<note>Button to connect to the relay.
Text for button to conect to Nostr Wallet Connect lightning wallet.</note>
</trans-unit>
<trans-unit id="Connect to Alby Wallet" xml:space="preserve">
<source>Connect to Alby Wallet</source>
<target state="new">Connect to Alby Wallet</target>
<note>Button to attach an Alby Wallet, a service that provides a Lightning wallet for zapping sats. Alby is the name of the service and should not be translated.</note>
</trans-unit>
<trans-unit id="Connect to Coinos" xml:space="preserve">
<source>Connect to Coinos</source>
<target state="new">Connect to Coinos</target>
@@ -6687,11 +6685,6 @@ Section title for deleting the user</note>
<target state="new">Please contact the person who provided the link, and ask for another link.</target>
<note>User-visible tip on what to do if a link contains a deprecated "nrelay" reference.</note>
</trans-unit>
<trans-unit id="Please contact the person who provided the link, and ask for another link. Also, this link may have sensitive information, please use caution before sharing it." xml:space="preserve">
<source>Please contact the person who provided the link, and ask for another link. Also, this link may have sensitive information, please use caution before sharing it.</source>
<target state="new">Please contact the person who provided the link, and ask for another link. Also, this link may have sensitive information, please use caution before sharing it.</target>
<note>User-visible tip on what to do if a link contains an unsupported "nsec" reference.</note>
</trans-unit>
<trans-unit id="Please copy the technical info and send it to our support team." xml:space="preserve">
<source>Please copy the technical info and send it to our support team.</source>
<target state="new">Please copy the technical info and send it to our support team.</target>
@@ -8202,11 +8195,6 @@ User confirm Yes</note>
<target state="new">You opened an invalid link. The link you tried to open refers to "nrelay", which has been deprecated and is not supported.</target>
<note>User-visible error description for a user who tries to open a deprecated "nrelay" link.</note>
</trans-unit>
<trans-unit id="You opened an invalid link. The link you tried to open refers to &quot;nsec&quot;, which is not supported." xml:space="preserve">
<source>You opened an invalid link. The link you tried to open refers to "nsec", which is not supported.</source>
<target state="new">You opened an invalid link. The link you tried to open refers to "nsec", which is not supported.</target>
<note>User-visible error description for a user who tries to open an unsupported "nsec" link.</note>
</trans-unit>
<trans-unit id="You unlocked" xml:space="preserve">
<source>You unlocked</source>
<target state="new">You unlocked</target>

View File

@@ -28,7 +28,7 @@
"comment" : "Amount of money required to publish to the Nostr relay. In English, this would look something like '10 sats / event', meaning it costs 10 sats to publish one event."
},
"%@ %@" : {
"comment" : "Sentence composed of 2 variables to describe how many imports were performed from loading a NostrScript. In source English, the first variable is the number of imports, and the second variable is 'Import' or 'Imports'.\nSentence composed of 2 variables to describe how many people are following a user. In source English, the first variable is the number of followers, and the second variable is 'Follower' or 'Followers'.\nSentence composed of 2 variables to describe how many people are in the follow pack. In source English, the first variable is the number of users, and the second variable is 'user' or 'users'.\nSentence composed of 2 variables to describe how many profiles a user is following. In source English, the first variable is the number of profiles being followed, and the second variable is 'Following'.\nSentence composed of 2 variables to describe how many quoted reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.\nSentence composed of 2 variables to describe how many reactions there are on a post. In source English, the first variable is the number of reactions, and the second variable is 'Reaction' or 'Reactions'.\nSentence composed of 2 variables to describe how many relay servers a user is connected. In source English, the first variable is the number of relay servers, and the second variable is 'Relay' or 'Relays'.\nSentence composed of 2 variables to describe how many relays a note was found on. In source English, the first variable is the number of relays, and the second variable is 'Relay' or 'Relays'.\nSentence composed of 2 variables to describe how many reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.\nSentence composed of 2 variables to describe how many zap payments there are on a post. In source English, the first variable is the number of zap payments, and the second variable is 'Zap' or 'Zaps'.",
"comment" : "Sentence composed of 2 variables to describe how many imports were performed from loading a NostrScript. In source English, the first variable is the number of imports, and the second variable is 'Import' or 'Imports'.\nSentence composed of 2 variables to describe how many people are following a user. In source English, the first variable is the number of followers, and the second variable is 'Follower' or 'Followers'.\nSentence composed of 2 variables to describe how many people are in the follow pack. In source English, the first variable is the number of users, and the second variable is 'user' or 'users'.\nSentence composed of 2 variables to describe how many profiles a user is following. In source English, the first variable is the number of profiles being followed, and the second variable is 'Following'.\nSentence composed of 2 variables to describe how many quoted reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.\nSentence composed of 2 variables to describe how many reactions there are on a post. In source English, the first variable is the number of reactions, and the second variable is 'Reaction' or 'Reactions'.\nSentence composed of 2 variables to describe how many relay servers a user is connected. In source English, the first variable is the number of relay servers, and the second variable is 'Relay' or 'Relays'.\nSentence composed of 2 variables to describe how many reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.\nSentence composed of 2 variables to describe how many zap payments there are on a post. In source English, the first variable is the number of zap payments, and the second variable is 'Zap' or 'Zaps'.",
"localizations" : {
"en-US" : {
"stringUnit" : {
@@ -423,6 +423,9 @@
"Connect" : {
"comment" : "Button to connect to the relay.\nText for button to conect to Nostr Wallet Connect lightning wallet."
},
"Connect to Alby Wallet" : {
"comment" : "Button to attach an Alby Wallet, a service that provides a Lightning wallet for zapping sats. Alby is the name of the service and should not be translated."
},
"Connect to Coinos" : {
"comment" : "Button to attach a Coinos Wallet, a service that provides a Lightning wallet for zapping sats. Coinos is the name of the service and should not be translated."
},
@@ -1349,9 +1352,6 @@
"Please contact the person who provided the link, and ask for another link." : {
"comment" : "User-visible tip on what to do if a link contains a deprecated \"nrelay\" reference."
},
"Please contact the person who provided the link, and ask for another link. Also, this link may have sensitive information, please use caution before sharing it." : {
"comment" : "User-visible tip on what to do if a link contains an unsupported \"nsec\" reference."
},
"Please copy the technical info and send it to our support team." : {
"comment" : "Tip on how to resolve issue when wallet returns an invalid response"
},
@@ -2254,9 +2254,6 @@
"You opened an invalid link. The link you tried to open refers to \"nrelay\", which has been deprecated and is not supported." : {
"comment" : "User-visible error description for a user who tries to open a deprecated \"nrelay\" link."
},
"You opened an invalid link. The link you tried to open refers to \"nsec\", which is not supported." : {
"comment" : "User-visible error description for a user who tries to open an unsupported \"nsec\" link."
},
"You unlocked" : {
"comment" : "Part 1 of 2 in message 'You unlocked automatic translations' the user gets when they sign up for Damus Purple"
},

Binary file not shown.

Binary file not shown.

View File

@@ -2,24 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>follow_pack_user_count</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOW_PACK_USERS@</string>
<key>FOLLOW_PACK_USERS</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>utilizador</string>
<key>many</key>
<string>utilizadores</string>
<key>other</key>
<string>utilizadores</string>
</dict>
</dict>
<key>followed_by_three_and_others</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
@@ -74,24 +56,6 @@
<string>A seguir</string>
</dict>
</dict>
<key>hellthread_notifications_disabled</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@HELLTHREAD_PROFILES@</string>
<key>HELLTHREAD_PROFILES</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>Ocultar notificações que marcam mais de %d perfil</string>
<key>many</key>
<string>Ocultar notificações que marcam mais de %d perfis</string>
<key>other</key>
<string>Ocultar notificações que marcam mais de %d perfis</string>
</dict>
</dict>
<key>imports_count</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
@@ -110,24 +74,6 @@
<string>importações</string>
</dict>
</dict>
<key>notes_from_three_and_others</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@OTHERS@</string>
<key>OTHERS</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>Notas de %2$@, %3$@, %4$@ &amp; %1$d outro da tua rede confiável</string>
<key>many</key>
<string>Notas de %2$@, %3$@, %4$@ &amp; %1$d outros da tua rede confiável</string>
<key>other</key>
<string>Notas de %2$@, %3$@, %4$@ &amp; %1$d outros da tua rede confiável</string>
</dict>
</dict>
<key>people_reposted_count</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
@@ -146,24 +92,6 @@
<string>%2$@ e mais %1$d republicaram</string>
</dict>
</dict>
<key>quoted_reposts_count</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@QUOTE_REPOSTS@</string>
<key>QUOTE_REPOSTS</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>Citação</string>
<key>many</key>
<string>Citações</string>
<key>other</key>
<string>Citações</string>
</dict>
</dict>
<key>reacted_tagged_in_3</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
@@ -344,6 +272,24 @@
<string>Republicações</string>
</dict>
</dict>
<key>quoted_reposts_count</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@QUOTE_REPOSTS@</string>
<key>QUOTE_REPOSTS</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>Citação</string>
<key>many</key>
<string>Citações</string>
<key>other</key>
<string>Citações</string>
</dict>
</dict>
<key>sats</key>
<dict>
<key>NSStringLocalizedFormatKey</key>

Binary file not shown.

Binary file not shown.