Merge branch 'master' into profile-markdown

This commit is contained in:
Lio李歐
2022-12-29 09:57:54 -08:00
committed by GitHub
42 changed files with 568 additions and 48 deletions

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 547 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

View File

@@ -122,6 +122,7 @@ struct ImageCarousel: View {
TabView {
ForEach(urls, id: \.absoluteString) { url in
Rectangle()
.foregroundColor(Color.clear)
.overlay {
KFAnimatedImage(url)
.configure { view in
@@ -136,6 +137,11 @@ struct ImageCarousel: View {
Text(url.absoluteString)
}
.id(url.absoluteString)
.contextMenu {
Button("Copy Image") {
UIPasteboard.general.string = url.absoluteString
}
}
}
}
}

View File

@@ -8,24 +8,38 @@
import SwiftUI
struct InvoiceView: View {
@Environment(\.colorScheme) var colorScheme
let invoice: Invoice
@State var showingSelectWallet: Bool = false
@State var inv: String = ""
var PayButton: some View {
Button("Pay") {
guard let url = URL(string: "lightning:" + invoice.string) else {
return
}
UIApplication.shared.open(url)
Button {
inv = invoice.string
showingSelectWallet = true
} label: {
RoundedRectangle(cornerRadius: 20)
.foregroundColor(colorScheme == .light ? .black : .white)
.overlay {
Text("Pay")
.fontWeight(.medium)
.foregroundColor(colorScheme == .light ? .white : .black)
}
}
//.buttonStyle(.bordered)
.onTapGesture {
// Temporary solution so that the "pay" button can be clicked (Yes we need an empty tap gesture)
}
.buttonStyle(.bordered)
}
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 20)
RoundedRectangle(cornerRadius: 10)
.foregroundColor(.secondary.opacity(0.1))
VStack(alignment: .trailing, spacing: 12) {
VStack(alignment: .leading, spacing: 12) {
HStack {
Label("", systemImage: "bolt.fill")
.foregroundColor(.orange)
@@ -36,9 +50,13 @@ struct InvoiceView: View {
Text("\(invoice.amount / 1000) sats")
.font(.title)
PayButton
.zIndex(5.0)
.frame(height: 50)
.zIndex(10.0)
}
.padding()
.padding(30)
}
.sheet(isPresented: $showingSelectWallet, onDismiss: {showingSelectWallet = false}) {
SelectWalletView(showingSelectWallet: $showingSelectWallet, invoice: $inv)
}
}
}

View File

@@ -88,7 +88,7 @@ struct ContentView: View {
self.active_sheet = .post
}
}
}
}.ignoresSafeArea(.keyboard, edges: .bottom)
}
.safeAreaInset(edge: .top) {
VStack(spacing: 0) {
@@ -228,6 +228,7 @@ struct ContentView: View {
}
TabBar(new_events: $home.new_events, selected: $selected_timeline, action: switch_timeline)
.padding()
}
.onAppear() {
self.connect()

View File

@@ -15,6 +15,19 @@
</array>
</dict>
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>muun</string>
<string>zeusln</string>
<string>zebedee</string>
<string>lightning</string>
<string>squarecash</string>
<string>phoenix</string>
<string>lnlink</string>
<string>strike</string>
<string>bluewallet</string>
<string>walletofsatoshi</string>
</array>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>

View File

@@ -190,6 +190,6 @@ class RelayPool {
func add_rw_relay(_ pool: RelayPool, _ url: String) {
let url_ = URL(string: url)!
try! pool.add_relay(url_, info: RelayInfo.rw)
try? pool.add_relay(url_, info: RelayInfo.rw)
}

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)!
}

39
damus/Util/LinkView.swift Normal file
View File

@@ -0,0 +1,39 @@
//
// LinkView.swift
// damus
//
// Created by Sam DuBois on 12/27/22.
//
import SwiftUI
import LinkPresentation
class CustomLinkView: LPLinkView {
override var intrinsicContentSize: CGSize { CGSize(width: 0, height: super.intrinsicContentSize.height) }
}
struct LinkViewRepresentable: UIViewRepresentable {
typealias UIViewType = CustomLinkView
var metadata: LPLinkMetadata?
var url: URL?
func makeUIView(context: Context) -> CustomLinkView {
if let metadata {
let linkView = CustomLinkView(metadata: metadata)
return linkView
}
if let url {
let linkView = CustomLinkView(url: url)
return linkView
}
return CustomLinkView()
}
func updateUIView(_ uiView: CustomLinkView, context: Context) {
}
}

View File

@@ -97,6 +97,12 @@ func parse_digit(_ p: Parser) -> Int? {
func parse_hex_char(_ p: Parser) -> Character? {
let ind = p.str.index(p.str.startIndex, offsetBy: p.pos)
// Check that we're within the bounds of p.str's length
if p.pos >= p.str.count {
return nil
}
if let c = p.str[ind].unicodeScalars.first {
// hex chars
let d = c.value

View File

@@ -17,9 +17,31 @@ struct AddRelayView: View {
VStack(alignment: .leading) {
Form {
Section("Add Relay") {
TextField("wss://some.relay.com", text: $relay)
.autocorrectionDisabled(true)
.textInputAutocapitalization(.never)
ZStack(alignment: .leading) {
HStack{
TextField("wss://some.relay.com", text: $relay)
.padding(2)
.padding(.leading, 25)
.autocorrectionDisabled(true)
.textInputAutocapitalization(.never)
Label("", systemImage: "xmark.circle.fill")
.foregroundColor(.blue)
.padding(.trailing, -25.0)
.opacity((relay == "") ? 0.0 : 1.0)
.onTapGesture {
self.relay = ""
}
}
Label("", systemImage: "doc.on.clipboard")
.padding(.leading, -10)
.onTapGesture {
if let pastedrelay = UIPasteboard.general.string {
self.relay = pastedrelay
}
}
}
}
}

View File

@@ -106,7 +106,7 @@ struct ChatView: View {
}
}
NoteContentView(privkey: damus_state.keypair.privkey, event: event, profiles: damus_state.profiles, show_images: should_show_images(contacts: damus_state.contacts, ev: event), artifacts: .just_content(event.content), size: .normal)
NoteContentView(privkey: damus_state.keypair.privkey, event: event, profiles: damus_state.profiles, show_images: should_show_images(contacts: damus_state.contacts, ev: event, our_pubkey: damus_state.pubkey), 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

@@ -102,12 +102,12 @@ struct ConfigView: View {
.navigationTitle("Settings")
.navigationBarTitleDisplayMode(.large)
.alert("Logout", isPresented: $confirm_logout) {
Button("Logout") {
notify(.logout, ())
}
Button("Cancel") {
confirm_logout = false
}
Button("Logout") {
notify(.logout, ())
}
} message: {
Text("Make sure your nsec account key is saved before you logout or you will lose access to this account")
}

View File

@@ -21,7 +21,9 @@ struct DMView: View {
Spacer()
}
NoteContentView(privkey: damus_state.keypair.privkey, event: event, profiles: damus_state.profiles, show_images: should_show_images(contacts: damus_state.contacts, ev: event), artifacts: .just_content(event.get_content(damus_state.keypair.privkey)), size: .normal)
let should_show_img = should_show_images(contacts: damus_state.contacts, ev: event, our_pubkey: damus_state.pubkey)
NoteContentView(privkey: damus_state.keypair.privkey, event: event, profiles: damus_state.profiles, 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

@@ -247,7 +247,9 @@ struct EventView: View {
.frame(maxWidth: .infinity, alignment: .leading)
}
NoteContentView(privkey: damus.keypair.privkey, event: event, profiles: damus.profiles, show_images: should_show_images(contacts: damus.contacts, ev: event), artifacts: .just_content(content), size: self.size)
let should_show_img = should_show_images(contacts: damus.contacts, ev: event, our_pubkey: damus.pubkey)
NoteContentView(privkey: damus.keypair.privkey, event: event, profiles: damus.profiles, show_images: should_show_img, artifacts: .just_content(content), size: self.size)
.frame(maxWidth: .infinity, alignment: .leading)
.allowsHitTesting(!embedded)
@@ -309,7 +311,10 @@ struct EventView: View {
}
// blame the porn bots for this code
func should_show_images(contacts: Contacts, ev: NostrEvent) -> Bool {
func should_show_images(contacts: Contacts, ev: NostrEvent, our_pubkey: String) -> Bool {
if ev.pubkey == our_pubkey {
return true
}
if contacts.is_in_friendosphere(ev.pubkey) {
return true
}

View File

@@ -14,7 +14,7 @@ struct FollowUserView: View {
static let markdown = Markdown()
var body: some View {
HStack(alignment: .top) {
HStack {
let pmodel = ProfileModel(pubkey: target.pubkey, damus: damus_state)
let followers = FollowersModel(damus_state: damus_state, target: target.pubkey)
let pv = ProfileView(damus_state: damus_state, profile: pmodel, followers: followers)
@@ -27,6 +27,8 @@ struct FollowUserView: View {
ProfileName(pubkey: target.pubkey, profile: profile, contacts: damus_state.contacts, show_friend_confirmed: false)
if let about = profile?.about {
Text(FollowUserView.markdown.process(about))
.lineLimit(3)
.font(.footnote)
}
}
@@ -53,6 +55,7 @@ struct FollowersView: View {
FollowUserView(target: .pubkey(pk), damus_state: damus_state)
}
}
.padding()
}
.navigationBarTitle("\(Profile.displayName(profile: profile, pubkey: whos))'s Followers")
.onAppear {
@@ -80,6 +83,7 @@ struct FollowingView: View {
FollowUserView(target: .pubkey(pk), damus_state: damus_state)
}
}
.padding()
}
.onAppear {
following.subscribe()

View File

@@ -76,14 +76,11 @@ struct TabBar: View {
VStack {
Divider()
HStack {
TabButton(timeline: .home, img: "house", selected: $selected, new_events: $new_events, action: action)
TabButton(timeline: .dms, img: "bubble.left.and.bubble.right", selected: $selected, new_events: $new_events, action: action)
TabButton(timeline: .search, img: "magnifyingglass.circle", selected: $selected, new_events: $new_events, action: action)
TabButton(timeline: .notifications, img: "bell", selected: $selected, new_events: $new_events, action: action)
TabButton(timeline: .home, img: "house", selected: $selected, new_events: $new_events, action: action).keyboardShortcut("1")
TabButton(timeline: .dms, img: "bubble.left.and.bubble.right", selected: $selected, new_events: $new_events, action: action).keyboardShortcut("2")
TabButton(timeline: .search, img: "magnifyingglass.circle", selected: $selected, new_events: $new_events, action: action).keyboardShortcut("3")
TabButton(timeline: .notifications, img: "bell", selected: $selected, new_events: $new_events, action: action).keyboardShortcut("4")
}
}
}
}

View File

@@ -6,14 +6,16 @@
//
import SwiftUI
import LinkPresentation
struct NoteArtifacts {
let content: String
let images: [URL]
let invoices: [Invoice]
let links: [URL]
static func just_content(_ content: String) -> NoteArtifacts {
NoteArtifacts(content: content, images: [], invoices: [])
NoteArtifacts(content: content, images: [], invoices: [], links: [])
}
}
@@ -21,6 +23,7 @@ func render_note_content(ev: NostrEvent, profiles: Profiles, privkey: String?) -
let blocks = ev.blocks(privkey)
var invoices: [Invoice] = []
var img_urls: [URL] = []
var link_urls: [URL] = []
let txt = blocks.reduce("") { str, block in
switch block {
case .mention(let m):
@@ -33,14 +36,20 @@ func render_note_content(ev: NostrEvent, profiles: Profiles, privkey: String?) -
invoices.append(invoice)
return str
case .url(let url):
// Handle Image URLs
if is_image_url(url) {
// Append Image
img_urls.append(url)
} else {
link_urls.append(url)
}
return str + url.absoluteString
return str
}
}
return NoteArtifacts(content: txt, images: img_urls, invoices: invoices)
return NoteArtifacts(content: txt, images: img_urls, invoices: invoices, links: link_urls)
}
func is_image_url(_ url: URL) -> Bool {
@@ -57,6 +66,7 @@ struct NoteContentView: View {
@State var artifacts: NoteArtifacts
@State var metaData: LPLinkMetadata? = nil
let size: EventViewKind
func MainContent() -> some View {
@@ -66,16 +76,33 @@ struct NoteContentView: View {
if show_images && artifacts.images.count > 0 {
ImageCarousel(urls: artifacts.images)
} else if !show_images && artifacts.images.count > 0 {
ImageCarousel(urls: artifacts.images)
.blur(radius: 10)
.overlay {
Rectangle()
.opacity(0.50)
}
.cornerRadius(10)
}
if artifacts.invoices.count > 0 {
InvoicesView(invoices: artifacts.invoices)
.frame(width: 200)
}
if show_images, self.metaData != nil {
LinkViewRepresentable(metadata: self.metaData)
} else {
ForEach(artifacts.links, id:\.self) { link in
LinkViewRepresentable(url: link)
.frame(height: 50)
}
}
}
}
var body: some View {
MainContent()
.animation(.easeInOut, value: metaData)
.onAppear() {
self.artifacts = render_note_content(ev: event, profiles: profiles, privkey: privkey)
}
@@ -95,6 +122,28 @@ struct NoteContentView: View {
}
}
}
.task {
if show_images, artifacts.links.count == 1 {
self.metaData = await getMetaData(for: artifacts.links.first!)
}
}
}
func getMetaData(for url: URL) async -> LPLinkMetadata? {
// iOS 15 is crashing for some reason
guard #available(iOS 16, *) else {
return nil
}
let provider = LPMetadataProvider()
do {
return try await provider.startFetchingMetadata(for: url)
} catch {
return nil
}
}
}
@@ -120,7 +169,7 @@ struct NoteContentView_Previews: PreviewProvider {
static var previews: some View {
let state = test_damus_state()
let content = "hi there https://jb55.com/s/Oct12-150217.png 5739a762ef6124dd.jpg"
let artifacts = NoteArtifacts(content: content, images: [], invoices: [])
let artifacts = NoteArtifacts(content: content, images: [], invoices: [], links: [])
NoteContentView(privkey: "", event: NostrEvent(content: content, pubkey: "pk"), profiles: state.profiles, show_images: true, artifacts: artifacts, size: .normal)
}
}

View File

@@ -23,6 +23,7 @@ func PostButton(action: @escaping () -> ()) -> some View {
radius: 3,
x: 3,
y: 3)
.keyboardShortcut("n", modifiers: [.command, .shift])
}
func PostButtonContainer(action: @escaping () -> ()) -> some View {

View File

@@ -119,6 +119,8 @@ struct ProfileView: View {
@StateObject var profile: ProfileModel
@StateObject var followers: FollowersModel
@State private var showingEditProfile = false
@State var showingSelectWallet: Bool = false
@State var inv: String = ""
@State var is_zoomed: Bool = false
@Environment(\.dismiss) var dismiss
@@ -126,9 +128,14 @@ struct ProfileView: View {
//@EnvironmentObject var profile: ProfileModel
func LNButton(_ url: URL, profile: Profile) -> some View {
func LNButton(lud06: String?, lud16: String?, profile: Profile) -> some View {
Button(action: {
UIApplication.shared.open(url)
if let l = lud06 {
inv = l
} else {
inv = lud16 ?? ""
}
showingSelectWallet = true
}) {
Image(systemName: "bolt.circle")
.symbolRenderingMode(.palette)
@@ -138,9 +145,11 @@ struct ProfileView: View {
Button {
UIPasteboard.general.string = profile.lnurl ?? ""
} label: {
Label("Copy LNUrl", systemImage: "doc.on.doc")
Label("Copy LNURL", systemImage: "doc.on.doc")
}
}
}.sheet(isPresented: $showingSelectWallet, onDismiss: {showingSelectWallet = false}) {
SelectWalletView(showingSelectWallet: $showingSelectWallet, invoice: $inv)
}
}
@@ -172,10 +181,10 @@ struct ProfileView: View {
}
Spacer()
if let profile = data {
if let lnuri = profile.lightning_uri {
LNButton(lnuri, profile: profile)
if (profile.lud06 != nil || profile.lud16 != nil) {
LNButton(lud06: profile.lud06, lud16: profile.lud16, profile: profile)
}
}

View File

@@ -0,0 +1,92 @@
//
// SelectWalletView.swift
// damus
//
// Created by Suhail Saqan on 12/22/22.
//
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
@Binding var invoice: String
@Environment(\.openURL) private var openURL
@State var invoice_copied: Bool = false
let generator = UIImpactFeedbackGenerator(style: .light)
let walletItems = try! JSONDecoder().decode([WalletItem].self, from: Constants.WALLETS)
var body: some View {
NavigationView {
Form {
Section("Copy invoice") {
HStack {
Text(invoice).font(.body)
.lineLimit(2)
.truncationMode(.tail)
Spacer()
Image(systemName: self.invoice_copied ? "checkmark.circle" : "doc.on.doc").foregroundColor(.blue)
}.clipShape(RoundedRectangle(cornerRadius: 5)).onTapGesture {
UIPasteboard.general.string = invoice
self.invoice_copied = true
generator.impactOccurred()
}
}
Section("Select a lightning wallet"){
List{
Button() {
if let url = URL(string: "lightning:\(invoice)"), UIApplication.shared.canOpenURL(url) {
openURL(url)
}
} label: {
HStack {
Text("Default Wallet").font(.body).foregroundColor(.blue)
}
}.buttonStyle(.plain)
ForEach(walletItems, id: \.self) { wallet in
Button() {
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.name).font(.body)
}
}.buttonStyle(.plain)
}
}.padding(.vertical, 2.5)
}
}.navigationBarTitle(Text("Pay the lightning invoice"), displayMode: .inline).navigationBarItems(trailing: Button(action: {
self.showingSelectWallet = false
}) {
Text("Done").bold()
})
}
}
}
struct SelectWalletView_Previews: PreviewProvider {
@State static var show: Bool = true
@State static var invoice: String = ""
static var previews: some View {
SelectWalletView(showingSelectWallet: $show, invoice: $invoice)
}
}

View File

@@ -245,7 +245,7 @@ struct ThreadV2View: View {
.buttonStyle(.plain)
.onAppear {
// TODO: find another solution to prevent layout shifting and layout blocking on large responses
reader.scrollTo("main", anchor: .center)
reader.scrollTo("main", anchor: .bottom)
}
}
}.background(GeometryReader { geometry in