refactor: settings and translation view

This commit is contained in:
William Casarin
2023-02-03 09:25:07 -08:00
parent 006f8d79e0
commit 1696e0365e
15 changed files with 266 additions and 257 deletions

View File

@@ -0,0 +1,138 @@
//
// TranslateButton.swift
// damus
//
// Created by William Casarin on 2023-02-02.
//
import SwiftUI
import NaturalLanguage
struct TranslateView: View {
let damus_state: DamusState
let event: NostrEvent
let size: EventViewKind
@State var checkingTranslationStatus: Bool = false
@State var currentLanguage: String = "en"
@State var noteLanguage: String? = nil
@State var translated_note: String? = nil
@State var show_translated_note: Bool = false
@State var translated_artifacts: NoteArtifacts? = nil
var TranslateButton: some View {
Button(NSLocalizedString("Translate Note", comment: "Button to translate note from different language.")) {
show_translated_note = true
}
.translate_button_style()
}
func Translated(lang: String, artifacts: NoteArtifacts) -> some View {
return Group {
Button(NSLocalizedString("Translated from \(lang)", comment: "Button to indicate that the note has been translated from a different language.")) {
show_translated_note = false
}
.translate_button_style()
Text(artifacts.content)
.font(eventviewsize_to_font(size))
.fixedSize(horizontal: false, vertical: true)
}
}
func CheckingStatus(lang: String) -> some View {
return Button(NSLocalizedString("Translating from \(lang)...", comment: "Button to indicate that the note is in the process of being translated from a different language.")) {
show_translated_note = false
}
.translate_button_style()
}
func MainContent(note_lang: String) -> some View {
return Group {
let languageName = Locale.current.localizedString(forLanguageCode: note_lang)
if let lang = languageName, show_translated_note {
if checkingTranslationStatus {
CheckingStatus(lang: lang)
} else if let artifacts = translated_artifacts {
Translated(lang: lang, artifacts: artifacts)
}
} else {
TranslateButton
}
}
}
var body: some View {
Group {
if let note_lang = noteLanguage, noteLanguage != currentLanguage {
MainContent(note_lang: note_lang)
} else {
Text("")
}
}
.task {
let translate_url = damus_state.settings.libretranslate_url
let api_key = damus_state.settings.libretranslate_api_key
guard noteLanguage == nil && !checkingTranslationStatus && translate_url != "" else {
return
}
checkingTranslationStatus = true
if #available(iOS 16, *) {
currentLanguage = Locale.current.language.languageCode?.identifier ?? "en"
} else {
currentLanguage = Locale.current.languageCode ?? "en"
}
// Rely on Apple's NLLanguageRecognizer to tell us which language it thinks the note is in.
let content = event.get_content(damus_state.keypair.privkey)
noteLanguage = NLLanguageRecognizer.dominantLanguage(for: content)?.rawValue ?? currentLanguage
if let lang = noteLanguage, noteLanguage != currentLanguage {
// If the detected dominant language is a variant, remove the variant component and just take the language part as LibreTranslate typically only supports the variant-less language.
if #available(iOS 16, *) {
noteLanguage = Locale.LanguageCode(stringLiteral: lang).identifier(.alpha2)
} else {
noteLanguage = Locale.canonicalLanguageIdentifier(from: lang)
}
}
guard let note_lang = noteLanguage else {
noteLanguage = currentLanguage
translated_note = nil
checkingTranslationStatus = false
return
}
if note_lang != currentLanguage {
do {
// If the note language is different from our language, send a translation request.
let translator = Translator(translate_url, apiKey: api_key)
translated_note = try await translator.translate(content, from: note_lang, to: currentLanguage)
} catch {
// If for whatever reason we're not able to figure out the language of the note, or translate the note, fail gracefully and do not retry. It's not the end of the world. Don't want to take down someone's translation server with an accidental denial of service attack.
noteLanguage = currentLanguage
translated_note = nil
}
}
if let translated = translated_note {
// Render translated note.
let blocks = event.get_blocks(content: translated)
translated_artifacts = render_blocks(blocks: blocks, profiles: damus_state.profiles, privkey: damus_state.keypair.privkey)
}
checkingTranslationStatus = false
}
}
}
struct TranslateView_Previews: PreviewProvider {
static var previews: some View {
let ds = test_damus_state()
TranslateView(damus_state: ds, event: test_event, size: .selected)
}
}

View File

@@ -89,7 +89,6 @@ struct ContentView: View {
@State var filter_state : FilterState = .posts_and_replies
@State private var isSideBarOpened = false
@StateObject var home: HomeModel = HomeModel()
@StateObject var user_settings = UserSettingsStore()
// connect retry timer
let timer = Timer.publish(every: 4, on: .main, in: .common).autoconnect()
@@ -112,7 +111,7 @@ struct ContentView: View {
.tabViewStyle(.page(indexDisplayMode: .never))
if privkey != nil {
PostButtonContainer(userSettings: user_settings) {
PostButtonContainer(is_left_handed: damus_state?.settings.left_handed ?? false) {
self.active_sheet = .post
}
}
@@ -286,7 +285,6 @@ struct ContentView: View {
.padding([.bottom], 8)
}
}
.environmentObject(user_settings)
.onAppear() {
self.connect()
//KingfisherManager.shared.cache.clearDiskCache()
@@ -563,7 +561,8 @@ struct ContentView: View {
dms: home.dms,
previews: PreviewCache(),
zaps: Zaps(our_pubkey: pubkey),
lnurls: LNUrls()
lnurls: LNUrls(),
settings: UserSettingsStore()
)
home.damus_state = self.damus_state!

View File

@@ -20,6 +20,7 @@ struct DamusState {
let previews: PreviewCache
let zaps: Zaps
let lnurls: LNUrls
let settings: UserSettingsStore
var pubkey: String {
return keypair.pubkey
@@ -31,6 +32,6 @@ struct DamusState {
static var empty: DamusState {
return DamusState.init(pool: RelayPool(), keypair: Keypair(pubkey: "", privkey: ""), likes: EventCounter(our_pubkey: ""), boosts: EventCounter(our_pubkey: ""), contacts: Contacts(our_pubkey: ""), tips: TipCounter(our_pubkey: ""), profiles: Profiles(), dms: DirectMessagesModel(our_pubkey: ""), previews: PreviewCache(), zaps: Zaps(our_pubkey: ""), lnurls: LNUrls())
return DamusState.init(pool: RelayPool(), keypair: Keypair(pubkey: "", privkey: ""), likes: EventCounter(our_pubkey: ""), boosts: EventCounter(our_pubkey: ""), contacts: Contacts(our_pubkey: ""), tips: TipCounter(our_pubkey: ""), profiles: Profiles(), dms: DirectMessagesModel(our_pubkey: ""), previews: PreviewCache(), zaps: Zaps(our_pubkey: ""), lnurls: LNUrls(), settings: UserSettingsStore())
}
}

View File

@@ -52,7 +52,7 @@ struct LightningInvoice<T> {
switch description {
case .description(let string):
return string
case .description_hash(let data):
case .description_hash:
return ""
}
}

View File

@@ -22,6 +22,22 @@ func get_default_wallet(_ pubkey: String) -> Wallet {
}
}
func get_libretranslate_server(_ pubkey: String) -> LibreTranslateServer? {
guard let server_name = UserDefaults.standard.string(forKey: "libretranslate_server") else {
return nil
}
return LibreTranslateServer(rawValue: server_name)
}
func get_libretranslate_url(_ pubkey: String, server: LibreTranslateServer) -> String? {
if let url = server.model.url {
return url
}
return UserDefaults.standard.object(forKey: "libretranslate_url") as? String
}
class UserSettingsStore: ObservableObject {
@Published var default_wallet: Wallet {
didSet {
@@ -82,15 +98,14 @@ class UserSettingsStore: ObservableObject {
init() {
// TODO: pubkey-scoped settings
let pubkey = ""
self.default_wallet = get_default_wallet("")
show_wallet_selector = should_show_wallet_selector("")
self.default_wallet = get_default_wallet(pubkey)
show_wallet_selector = should_show_wallet_selector(pubkey)
left_handed = UserDefaults.standard.object(forKey: "left_handed") as? Bool ?? false
if let translationServerName = UserDefaults.standard.string(forKey: "libretranslate_server"),
let translationServer = LibreTranslateServer(rawValue: translationServerName) {
self.libretranslate_server = translationServer
libretranslate_url = translationServer.model.url ?? UserDefaults.standard.object(forKey: "libretranslate_url") as? String ?? ""
if let server = get_libretranslate_server(pubkey) {
self.libretranslate_server = server
self.libretranslate_url = get_libretranslate_url(pubkey, server: server) ?? ""
} else {
// Note from @tyiu:
// Default server is disabled by default for now until we gain some confidence that it is working well in production.
@@ -101,7 +116,7 @@ class UserSettingsStore: ObservableObject {
libretranslate_server = .none
libretranslate_url = ""
}
do {
libretranslate_api_key = try Vault.getPrivateKey(keychainConfiguration: DamusLibreTranslateKeychainConfiguration())
} catch {

View File

@@ -96,17 +96,24 @@ struct ChatView: View {
if let ref_id = thread.replies.lookup(event.id) {
if !is_reply_to_prev() {
/*
ReplyQuoteView(keypair: damus_state.keypair, quoter: event, event_id: ref_id, profiles: damus_state.profiles, previews: damus_state.previews)
.frame(maxHeight: expand_reply ? nil : 100)
.environmentObject(thread)
.onTapGesture {
expand_reply = !expand_reply
}
*/
ReplyDescription
}
}
NoteContentView(keypair: damus_state.keypair, event: event, profiles: damus_state.profiles, previews: damus_state.previews, show_images: should_show_images(contacts: damus_state.contacts, ev: event, our_pubkey: damus_state.pubkey), artifacts: .just_content(event.content), size: .normal)
let show_images = should_show_images(contacts: damus_state.contacts, ev: event, our_pubkey: damus_state.pubkey)
NoteContentView(damus_state: damus_state,
event: event,
show_images: show_images,
artifacts: .just_content(event.content),
size: .normal)
if is_active || next_ev == nil || next_ev!.pubkey != event.pubkey {
let bar = make_actionbar_model(ev: event, damus: damus_state)

View File

@@ -19,13 +19,15 @@ struct ConfigView: View {
@State var privkey_copied: Bool = false
@State var pubkey_copied: Bool = false
@State var delete_text: String = ""
@EnvironmentObject var user_settings: UserSettingsStore
@ObservedObject var settings: UserSettingsStore
let generator = UIImpactFeedbackGenerator(style: .light)
init(state: DamusState) {
self.state = state
_privkey = State(initialValue: self.state.keypair.privkey_bech32 ?? "")
_settings = ObservedObject(initialValue: state.settings)
}
// TODO: (jb55) could be more general but not gonna worry about it atm
@@ -72,9 +74,9 @@ struct ConfigView: View {
}
Section(NSLocalizedString("Wallet Selector", comment: "Section title for selection of wallet.")) {
Toggle(NSLocalizedString("Show wallet selector", comment: "Toggle to show or hide selection of wallet."), isOn: $user_settings.show_wallet_selector).toggleStyle(.switch)
Toggle(NSLocalizedString("Show wallet selector", comment: "Toggle to show or hide selection of wallet."), isOn: $settings.show_wallet_selector).toggleStyle(.switch)
Picker(NSLocalizedString("Select default wallet", comment: "Prompt selection of user's default wallet"),
selection: $user_settings.default_wallet) {
selection: $settings.default_wallet) {
ForEach(Wallet.allCases, id: \.self) { wallet in
Text(wallet.model.displayName)
.tag(wallet.model.tag)
@@ -83,28 +85,28 @@ struct ConfigView: View {
}
Section(NSLocalizedString("LibreTranslate Translations", comment: "Section title for selecting the server that hosts the LibreTranslate machine translation API.")) {
Picker(NSLocalizedString("Server", comment: "Prompt selection of LibreTranslate server to perform machine translations on notes"), selection: $user_settings.libretranslate_server) {
Picker(NSLocalizedString("Server", comment: "Prompt selection of LibreTranslate server to perform machine translations on notes"), selection: $settings.libretranslate_server) {
ForEach(LibreTranslateServer.allCases, id: \.self) { server in
Text(server.model.displayName)
.tag(server.model.tag)
}
}
if user_settings.libretranslate_server != .none {
TextField(NSLocalizedString("URL", comment: "Example URL to LibreTranslate server"), text: $user_settings.libretranslate_url)
if settings.libretranslate_server != .none {
TextField(NSLocalizedString("URL", comment: "Example URL to LibreTranslate server"), text: $settings.libretranslate_url)
.disableAutocorrection(true)
.disabled(user_settings.libretranslate_server != .custom)
.disabled(settings.libretranslate_server != .custom)
.autocapitalization(UITextAutocapitalizationType.none)
HStack {
if show_libretranslate_api_key {
TextField(NSLocalizedString("API Key (optional)", comment: "Example URL to LibreTranslate server"), text: $user_settings.libretranslate_api_key)
TextField(NSLocalizedString("API Key (optional)", comment: "Example URL to LibreTranslate server"), text: $settings.libretranslate_api_key)
.disableAutocorrection(true)
.autocapitalization(UITextAutocapitalizationType.none)
Button(NSLocalizedString("Hide API Key", comment: "Button to hide the LibreTranslate server API key.")) {
show_libretranslate_api_key = false
}
} else {
SecureField(NSLocalizedString("API Key (optional)", comment: "Example URL to LibreTranslate server"), text: $user_settings.libretranslate_api_key)
SecureField(NSLocalizedString("API Key (optional)", comment: "Example URL to LibreTranslate server"), text: $settings.libretranslate_api_key)
.disableAutocorrection(true)
.autocapitalization(UITextAutocapitalizationType.none)
Button(NSLocalizedString("Show API Key", comment: "Button to hide the LibreTranslate server API key.")) {
@@ -116,7 +118,7 @@ struct ConfigView: View {
}
Section(NSLocalizedString("Left Handed", comment: "Moves the post button to the left side of the screen")) {
Toggle(NSLocalizedString("Left Handed", comment: "Moves the post button to the left side of the screen"), isOn: $user_settings.left_handed)
Toggle(NSLocalizedString("Left Handed", comment: "Moves the post button to the left side of the screen"), isOn: $settings.left_handed)
.toggleStyle(.switch)
}

View File

@@ -23,7 +23,7 @@ struct DMView: View {
let should_show_img = should_show_images(contacts: damus_state.contacts, ev: event, our_pubkey: damus_state.pubkey)
NoteContentView(keypair: damus_state.keypair, event: event, profiles: damus_state.profiles, previews: damus_state.previews, show_images: should_show_img, artifacts: .just_content(event.get_content(damus_state.keypair.privkey)), size: .normal)
NoteContentView(damus_state: damus_state, event: event, show_images: should_show_img, artifacts: .just_content(event.get_content(damus_state.keypair.privkey)), size: .normal)
.foregroundColor(is_ours ? Color.white : Color.primary)
.padding(10)
.background(is_ours ? Color.accentColor : Color.secondary.opacity(0.15))

View File

@@ -23,7 +23,7 @@ struct EventBody: View {
let should_show_img = should_show_images(contacts: damus_state.contacts, ev: event, our_pubkey: damus_state.pubkey, booster_pubkey: nil)
NoteContentView(privkey: damus_state.keypair.privkey, event: event, profiles: damus_state.profiles, previews: damus_state.previews, show_images: should_show_img, artifacts: .just_content(content), size: size)
NoteContentView(damus_state: damus_state, event: event, show_images: should_show_img, artifacts: .just_content(content), size: size)
.frame(maxWidth: .infinity, alignment: .leading)
}
}

View File

@@ -13,108 +13,16 @@ import NaturalLanguage
import FoundationNetworking
#endif
struct NoteArtifacts {
let content: AttributedString
let images: [URL]
let invoices: [Invoice]
let links: [URL]
static func just_content(_ content: String) -> NoteArtifacts {
NoteArtifacts(content: AttributedString(stringLiteral: content), images: [], invoices: [], links: [])
}
}
func render_note_content(ev: NostrEvent, profiles: Profiles, privkey: String?) -> NoteArtifacts {
let blocks = ev.blocks(privkey)
return render_blocks(blocks: blocks, profiles: profiles, privkey: privkey)
}
func render_blocks(blocks: [Block], profiles: Profiles, privkey: String?) -> NoteArtifacts {
var invoices: [Invoice] = []
var img_urls: [URL] = []
var link_urls: [URL] = []
let txt: AttributedString = blocks.reduce("") { str, block in
switch block {
case .mention(let m):
return str + mention_str(m, profiles: profiles)
case .text(let txt):
return str + AttributedString(stringLiteral: txt)
case .hashtag(let htag):
return str + hashtag_str(htag)
case .invoice(let invoice):
invoices.append(invoice)
return str
case .url(let url):
// Handle Image URLs
if is_image_url(url) {
// Append Image
img_urls.append(url)
return str
} else {
link_urls.append(url)
return str + url_str(url)
}
}
}
return NoteArtifacts(content: txt, images: img_urls, invoices: invoices, links: link_urls)
}
func is_image_url(_ url: URL) -> Bool {
let str = url.lastPathComponent.lowercased()
return str.hasSuffix("png") || str.hasSuffix("jpg") || str.hasSuffix("jpeg") || str.hasSuffix("gif")
}
struct NoteContentView: View {
let keypair: Keypair
let damus_state: DamusState
let event: NostrEvent
let profiles: Profiles
let previews: PreviewCache
let show_images: Bool
@State var checkingTranslationStatus: Bool = false
@State var currentLanguage: String = "en"
@State var noteLanguage: String? = nil
@State var translated_note: String? = nil
@State var show_translated_note: Bool = false
@State var translated_artifacts: NoteArtifacts? = nil
@State var artifacts: NoteArtifacts
@State var preview: LinkViewRepresentable? = nil
let size: EventViewKind
@EnvironmentObject var user_settings: UserSettingsStore
var TranslateButton: some View {
Group {
let languageName = Locale.current.localizedString(forLanguageCode: noteLanguage!)
if show_translated_note {
if checkingTranslationStatus {
Button(NSLocalizedString("Translating from \(languageName!)...", comment: "Button to indicate that the note is in the process of being translated from a different language.")) {
show_translated_note = false
}
.translate_button_style()
} else if translated_artifacts != nil {
Button(NSLocalizedString("Translated from \(languageName!)", comment: "Button to indicate that the note has been translated from a different language.")) {
show_translated_note = false
}
.translate_button_style()
Text(translated_artifacts!.content)
.font(eventviewsize_to_font(size))
.fixedSize(horizontal: false, vertical: true)
}
} else {
Button(NSLocalizedString("Translate Note", comment: "Button to translate note from different language.")) {
show_translated_note = true
}
.translate_button_style()
}
}
}
@State var preview: LinkViewRepresentable? = nil
func MainContent() -> some View {
return VStack(alignment: .leading) {
@@ -122,8 +30,8 @@ struct NoteContentView: View {
.font(eventviewsize_to_font(size))
.fixedSize(horizontal: false, vertical: true)
if size == .selected && noteLanguage != nil && noteLanguage != currentLanguage {
TranslateButton
if size == .selected {
TranslateView(damus_state: damus_state, event: event, size: size)
}
if show_images && artifacts.images.count > 0 {
@@ -138,7 +46,7 @@ struct NoteContentView: View {
.cornerRadius(10)
}
if artifacts.invoices.count > 0 {
InvoicesView(our_pubkey: keypair.pubkey, invoices: artifacts.invoices)
InvoicesView(our_pubkey: damus_state.keypair.pubkey, invoices: artifacts.invoices)
}
if let preview = self.preview, show_images {
@@ -157,16 +65,16 @@ struct NoteContentView: View {
var body: some View {
MainContent()
.onAppear() {
self.artifacts = render_note_content(ev: event, profiles: profiles, privkey: keypair.privkey)
self.artifacts = render_note_content(ev: event, profiles: damus_state.profiles, privkey: damus_state.keypair.privkey)
}
.onReceive(handle_notify(.profile_updated)) { notif in
let profile = notif.object as! ProfileUpdate
let blocks = event.blocks(keypair.privkey)
let blocks = event.blocks(damus_state.keypair.privkey)
for block in blocks {
switch block {
case .mention(let m):
if m.type == .pubkey && m.ref.ref_id == profile.pubkey {
self.artifacts = render_note_content(ev: event, profiles: profiles, privkey: keypair.privkey)
self.artifacts = render_note_content(ev: event, profiles: damus_state.profiles, privkey: damus_state.keypair.privkey)
}
case .text: return
case .hashtag: return
@@ -176,7 +84,7 @@ struct NoteContentView: View {
}
}
.task {
if let preview = previews.lookup(self.event.id) {
if let preview = damus_state.previews.lookup(self.event.id) {
switch preview {
case .value(let view):
self.preview = view
@@ -190,54 +98,10 @@ struct NoteContentView: View {
let meta = await getMetaData(for: artifacts.links.first!)
let view = meta.map { LinkViewRepresentable(meta: .linkmeta($0)) }
previews.store(evid: self.event.id, preview: view)
damus_state.previews.store(evid: self.event.id, preview: view)
self.preview = view
}
if size == .selected && noteLanguage == nil && !checkingTranslationStatus && user_settings.libretranslate_url != "" {
checkingTranslationStatus = true
if #available(iOS 16, *) {
currentLanguage = Locale.current.language.languageCode?.identifier ?? "en"
} else {
currentLanguage = Locale.current.languageCode ?? "en"
}
// Rely on Apple's NLLanguageRecognizer to tell us which language it thinks the note is in.
noteLanguage = NLLanguageRecognizer.dominantLanguage(for: event.content)?.rawValue ?? currentLanguage
if noteLanguage != currentLanguage {
// If the detected dominant language is a variant, remove the variant component and just take the language part as LibreTranslate typically only supports the variant-less language.
if #available(iOS 16, *) {
noteLanguage = Locale.LanguageCode(stringLiteral: noteLanguage!).identifier(.alpha2)
} else {
noteLanguage = Locale.canonicalLanguageIdentifier(from: noteLanguage!)
}
}
if noteLanguage == nil {
noteLanguage = currentLanguage
translated_note = nil
} else if noteLanguage != currentLanguage {
do {
// If the note language is different from our language, send a translation request.
let translator = Translator(user_settings.libretranslate_url, apiKey: user_settings.libretranslate_api_key)
translated_note = try await translator.translate(event.content, from: noteLanguage!, to: currentLanguage)
} catch {
// If for whatever reason we're not able to figure out the language of the note, or translate the note, fail gracefully and do not retry. It's not the end of the world. Don't want to take down someone's translation server with an accidental denial of service attack.
noteLanguage = currentLanguage
translated_note = nil
}
}
if translated_note != nil {
// Render translated note.
let blocks = event.get_blocks(content: translated_note!)
translated_artifacts = render_blocks(blocks: blocks, profiles: profiles, privkey: privkey)
}
checkingTranslationStatus = false
}
}
}
@@ -372,7 +236,7 @@ struct NoteContentView_Previews: PreviewProvider {
let state = test_damus_state()
let content = "hi there ¯\\_(ツ)_/¯ https://jb55.com/s/Oct12-150217.png 5739a762ef6124dd.jpg"
let artifacts = NoteArtifacts(content: AttributedString(stringLiteral: content), images: [], invoices: [], links: [])
NoteContentView(privkey: "", event: NostrEvent(content: content, pubkey: "pk"), profiles: state.profiles, previews: PreviewCache(), show_images: true, artifacts: artifacts, size: .normal)
NoteContentView(damus_state: state, event: NostrEvent(content: content, pubkey: "pk"), show_images: true, artifacts: artifacts, size: .normal)
}
}
@@ -385,3 +249,56 @@ extension View {
.padding([.top, .bottom], 10)
}
}
struct NoteArtifacts {
let content: AttributedString
let images: [URL]
let invoices: [Invoice]
let links: [URL]
static func just_content(_ content: String) -> NoteArtifacts {
NoteArtifacts(content: AttributedString(stringLiteral: content), images: [], invoices: [], links: [])
}
}
func render_note_content(ev: NostrEvent, profiles: Profiles, privkey: String?) -> NoteArtifacts {
let blocks = ev.blocks(privkey)
return render_blocks(blocks: blocks, profiles: profiles, privkey: privkey)
}
func render_blocks(blocks: [Block], profiles: Profiles, privkey: String?) -> NoteArtifacts {
var invoices: [Invoice] = []
var img_urls: [URL] = []
var link_urls: [URL] = []
let txt: AttributedString = blocks.reduce("") { str, block in
switch block {
case .mention(let m):
return str + mention_str(m, profiles: profiles)
case .text(let txt):
return str + AttributedString(stringLiteral: txt)
case .hashtag(let htag):
return str + hashtag_str(htag)
case .invoice(let invoice):
invoices.append(invoice)
return str
case .url(let url):
// Handle Image URLs
if is_image_url(url) {
// Append Image
img_urls.append(url)
return str
} else {
link_urls.append(url)
return str + url_str(url)
}
}
}
return NoteArtifacts(content: txt, images: img_urls, invoices: invoices, links: link_urls)
}
func is_image_url(_ url: URL) -> Bool {
let str = url.lastPathComponent.lowercased()
return str.hasSuffix("png") || str.hasSuffix("jpg") || str.hasSuffix("jpeg") || str.hasSuffix("gif")
}

View File

@@ -34,8 +34,7 @@ func PostButton(action: @escaping () -> ()) -> some View {
.keyboardShortcut("n", modifiers: [.command, .shift])
}
func PostButtonContainer(userSettings: UserSettingsStore, action: @escaping () -> Void) -> some View {
let is_left_handed = userSettings.left_handed.self
func PostButtonContainer(is_left_handed: Bool, action: @escaping () -> Void) -> some View {
return VStack {
Spacer()

View File

@@ -116,7 +116,6 @@ struct ProfileView: View {
@State var is_zoomed: Bool = false
@State var show_share_sheet: Bool = false
@State var action_sheet_presented: Bool = false
@EnvironmentObject var user_settings: UserSettingsStore
@Environment(\.dismiss) var dismiss
@Environment(\.colorScheme) var colorScheme
@@ -142,10 +141,10 @@ struct ProfileView: View {
func LNButton(lnurl: String, profile: Profile) -> some View {
Button(action: {
if user_settings.show_wallet_selector {
if damus_state.settings.show_wallet_selector {
showing_select_wallet = true
} else {
open_with_wallet(wallet: user_settings.default_wallet.model, invoice: lnurl)
open_with_wallet(wallet: damus_state.settings.default_wallet.model, invoice: lnurl)
}
}) {
Image(systemName: "bolt.circle")
@@ -162,7 +161,6 @@ struct ProfileView: View {
.cornerRadius(24)
.sheet(isPresented: $showing_select_wallet, onDismiss: {showing_select_wallet = false}) {
SelectWalletView(showingSelectWallet: $showing_select_wallet, our_pubkey: damus_state.pubkey, invoice: lnurl)
.environmentObject(user_settings)
}
}
@@ -409,7 +407,7 @@ struct ProfileView_Previews: PreviewProvider {
func test_damus_state() -> DamusState {
let pubkey = "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"
let damus = DamusState(pool: RelayPool(), keypair: Keypair(pubkey: pubkey, privkey: "privkey"), likes: EventCounter(our_pubkey: pubkey), boosts: EventCounter(our_pubkey: pubkey), contacts: Contacts(our_pubkey: pubkey), tips: TipCounter(our_pubkey: pubkey), profiles: Profiles(), dms: DirectMessagesModel(our_pubkey: pubkey), previews: PreviewCache(), zaps: Zaps(our_pubkey: pubkey), lnurls: LNUrls())
let damus = DamusState.empty
let prof = Profile(name: "damus", display_name: "damus", about: "iOS app!", picture: "https://damus.io/img/logo.png", banner: "", website: "https://damus.io", lud06: nil, lud16: "jb55@sendsats.lol", nip05: "damus.io")
let tsprof = TimestampedProfile(profile: prof, timestamp: 0)

View File

@@ -1,65 +0,0 @@
//
// SwiftUIView.swift
// damus
//
// Created by William Casarin on 2022-04-19.
//
import SwiftUI
struct ReplyQuoteView: View {
let keypair: Keypair
let quoter: NostrEvent
let event_id: String
let profiles: Profiles
let previews: PreviewCache
@EnvironmentObject var thread: ThreadModel
func MainContent(event: NostrEvent) -> some View {
HStack(alignment: .top) {
Rectangle()
.frame(width: 2)
.padding([.leading], 4)
.foregroundColor(.accentColor)
VStack(alignment: .leading) {
HStack(alignment: .top) {
ProfilePicView(pubkey: event.pubkey, size: 16, highlight: .reply, profiles: profiles)
Text(Profile.displayName(profile: profiles.lookup(id: event.pubkey), pubkey: event.pubkey))
.foregroundColor(.accentColor)
Text("\(format_relative_time(event.created_at))", comment: "Amount of time that has passed since reply quote event occurred.")
.foregroundColor(.gray)
}
NoteContentView(keypair: keypair, event: event, profiles: profiles, previews: previews, show_images: false, artifacts: .just_content(event.content), size: .normal)
.font(.callout)
.foregroundColor(.accentColor)
//Spacer()
}
//.border(Color.red)
}
//.border(Color.green)
}
var body: some View {
Group {
if let event = thread.lookup(event_id) {
MainContent(event: event)
.padding(4)
.frame(maxWidth: .infinity, alignment: .leading)
.contentShape(Rectangle())
}
}
}
}
struct ReplyQuoteView_Previews: PreviewProvider {
static var previews: some View {
let s = test_damus_state()
let quoter = NostrEvent(content: "a\nb\nc", pubkey: "pubkey")
ReplyQuoteView(keypair: s.keypair, quoter: quoter, event_id: "pubkey2", profiles: s.profiles, previews: PreviewCache())
.environmentObject(ThreadModel(event: quoter, damus_state: s))
}
}

View File

@@ -10,9 +10,7 @@ import SwiftUI
struct SideMenuView: View {
let damus_state: DamusState
@Binding var isSidebarVisible: Bool
@State var confirm_logout: Bool = false
@EnvironmentObject var user_settings: UserSettingsStore
@State private var showQRCode = false
@@ -121,7 +119,7 @@ struct SideMenuView: View {
.foregroundColor(textColor())
}
NavigationLink(destination: ConfigView(state: damus_state).environmentObject(user_settings)) {
NavigationLink(destination: ConfigView(state: damus_state)) {
Label(NSLocalizedString("Settings", comment: "Sidebar menu label for accessing the app settings"), systemImage: "gear")
.font(.title2)
.foregroundColor(textColor())