Merge branch 'damus-io:master' into sidebar
This commit is contained in:
@@ -56,7 +56,7 @@ damus implements the following [Nostr Implementation Possibilities][nips]
|
|||||||
- Formatting Notes (may not format as intended in other web clients)
|
- Formatting Notes (may not format as intended in other web clients)
|
||||||
- Italics: 1 asterisk `*italic*`
|
- Italics: 1 asterisk `*italic*`
|
||||||
- Bold: 2 asterisk `**bold**`
|
- Bold: 2 asterisk `**bold**`
|
||||||
- Strikethrough: 2 tildes `~~strikethrough~~`
|
- Strikethrough: 1 tildes `~strikethrough~`
|
||||||
- Code: 1 back-tick ``code``
|
- Code: 1 back-tick ``code``
|
||||||
|
|
||||||
#### 💬 Encrypted DMs (chat app, bottom navigation)
|
#### 💬 Encrypted DMs (chat app, bottom navigation)
|
||||||
|
|||||||
@@ -1098,7 +1098,7 @@
|
|||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = damus/damus.entitlements;
|
CODE_SIGN_ENTITLEMENTS = damus/damus.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 4;
|
CURRENT_PROJECT_VERSION = 5;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"damus/Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"damus/Preview Content\"";
|
||||||
DEVELOPMENT_TEAM = XK7H4JAB3D;
|
DEVELOPMENT_TEAM = XK7H4JAB3D;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@@ -1138,7 +1138,7 @@
|
|||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = damus/damus.entitlements;
|
CODE_SIGN_ENTITLEMENTS = damus/damus.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 4;
|
CURRENT_PROJECT_VERSION = 5;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"damus/Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"damus/Preview Content\"";
|
||||||
DEVELOPMENT_TEAM = XK7H4JAB3D;
|
DEVELOPMENT_TEAM = XK7H4JAB3D;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
|
|||||||
@@ -94,9 +94,9 @@ struct ContentView: View {
|
|||||||
var PostingTimelineView: some View {
|
var PostingTimelineView: some View {
|
||||||
VStack {
|
VStack {
|
||||||
TabView(selection: $filter_state) {
|
TabView(selection: $filter_state) {
|
||||||
ContentTimelineView
|
contentTimelineView(filter: posts_filter_event)
|
||||||
.tag(FilterState.posts)
|
.tag(FilterState.posts)
|
||||||
ContentTimelineView
|
contentTimelineView(filter: posts_and_replies_filter_event)
|
||||||
.tag(FilterState.posts_and_replies)
|
.tag(FilterState.posts_and_replies)
|
||||||
}
|
}
|
||||||
.tabViewStyle(.page(indexDisplayMode: .never))
|
.tabViewStyle(.page(indexDisplayMode: .never))
|
||||||
@@ -114,10 +114,10 @@ struct ContentView: View {
|
|||||||
.ignoresSafeArea(.keyboard)
|
.ignoresSafeArea(.keyboard)
|
||||||
}
|
}
|
||||||
|
|
||||||
var ContentTimelineView: some View {
|
func contentTimelineView(filter: (@escaping (NostrEvent) -> Bool)) -> some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
if let damus = self.damus_state {
|
if let damus = self.damus_state {
|
||||||
TimelineView(events: $home.events, loading: $home.loading, damus: damus, show_friend_icon: false, filter: filter_event)
|
TimelineView(events: $home.events, loading: $home.loading, damus: damus, show_friend_icon: false, filter: filter)
|
||||||
}
|
}
|
||||||
if privkey != nil {
|
if privkey != nil {
|
||||||
PostButtonContainer {
|
PostButtonContainer {
|
||||||
@@ -127,6 +127,14 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func posts_and_replies_filter_event(_ ev: NostrEvent) -> Bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func posts_filter_event(_ ev: NostrEvent) -> Bool {
|
||||||
|
return !ev.is_reply(nil)
|
||||||
|
}
|
||||||
|
|
||||||
var FiltersView: some View {
|
var FiltersView: some View {
|
||||||
VStack{
|
VStack{
|
||||||
Picker("Filter State", selection: $filter_state) {
|
Picker("Filter State", selection: $filter_state) {
|
||||||
@@ -137,14 +145,6 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func filter_event(_ ev: NostrEvent) -> Bool {
|
|
||||||
if self.filter_state == .posts {
|
|
||||||
return !ev.is_reply(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func MainContent(damus: DamusState) -> some View {
|
func MainContent(damus: DamusState) -> some View {
|
||||||
VStack {
|
VStack {
|
||||||
NavigationLink(destination: MaybeProfileView, isActive: $profile_open) {
|
NavigationLink(destination: MaybeProfileView, isActive: $profile_open) {
|
||||||
|
|||||||
@@ -112,27 +112,30 @@ func load_profiles(profiles_subid: String, relay_id: String, events: [NostrEvent
|
|||||||
let authors = find_profiles_to_fetch(profiles: damus_state.profiles, events: events)
|
let authors = find_profiles_to_fetch(profiles: damus_state.profiles, events: events)
|
||||||
filter.authors = authors
|
filter.authors = authors
|
||||||
|
|
||||||
if !authors.isEmpty {
|
guard !authors.isEmpty else {
|
||||||
print("loading \(authors.count) profiles from \(relay_id)")
|
return
|
||||||
damus_state.pool.subscribe_to(sub_id: profiles_subid, filters: [filter], to: [relay_id]) { sub_id, conn_ev in
|
}
|
||||||
let (sid, done) = handle_subid_event(pool: damus_state.pool, relay_id: relay_id, ev: conn_ev) { sub_id, ev in
|
|
||||||
guard sub_id == profiles_subid else {
|
print("loading \(authors.count) profiles from \(relay_id)")
|
||||||
return
|
|
||||||
}
|
damus_state.pool.subscribe_to(sub_id: profiles_subid, filters: [filter], to: [relay_id]) { sub_id, conn_ev in
|
||||||
|
let (sid, done) = handle_subid_event(pool: damus_state.pool, relay_id: relay_id, ev: conn_ev) { sub_id, ev in
|
||||||
if ev.known_kind == .metadata {
|
guard sub_id == profiles_subid else {
|
||||||
process_metadata_event(profiles: damus_state.profiles, ev: ev)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
guard done && sid == profiles_subid else {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
print("done loading \(authors.count) profiles from \(relay_id)")
|
if ev.known_kind == .metadata {
|
||||||
damus_state.pool.unsubscribe(sub_id: profiles_subid, to: [relay_id])
|
process_metadata_event(profiles: damus_state.profiles, ev: ev)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
guard done && sid == profiles_subid else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
print("done loading \(authors.count) profiles from \(relay_id)")
|
||||||
|
damus_state.pool.unsubscribe(sub_id: profiles_subid, to: [relay_id])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,32 @@ func parse_nostr_ref_uri(_ p: Parser) -> ReferencedId? {
|
|||||||
return ReferencedId(ref_id: pk, relay_id: nil, key: typ)
|
return ReferencedId(ref_id: pk, relay_id: nil, key: typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func decode_universal_link(_ s: String) -> NostrLink? {
|
||||||
|
var uri = s.replacingOccurrences(of: "https://damus.io/r/", with: "")
|
||||||
|
uri = uri.replacingOccurrences(of: "https://damus.io/", with: "")
|
||||||
|
uri = uri.replacingOccurrences(of: "/", with: "")
|
||||||
|
|
||||||
|
guard let decoded = try? bech32_decode(uri) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let h = hex_encode(decoded.data)
|
||||||
|
|
||||||
|
if decoded.hrp == "note" {
|
||||||
|
return .ref(ReferencedId(ref_id: h, relay_id: nil, key: "e"))
|
||||||
|
} else if decoded.hrp == "npub" {
|
||||||
|
return .ref(ReferencedId(ref_id: h, relay_id: nil, key: "p"))
|
||||||
|
}
|
||||||
|
// TODO: handle nprofile, etc
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func decode_nostr_uri(_ s: String) -> NostrLink? {
|
func decode_nostr_uri(_ s: String) -> NostrLink? {
|
||||||
|
if s.starts(with: "https://damus.io/") {
|
||||||
|
return decode_universal_link(s)
|
||||||
|
}
|
||||||
|
|
||||||
var uri = s.replacingOccurrences(of: "nostr://", with: "")
|
var uri = s.replacingOccurrences(of: "nostr://", with: "")
|
||||||
uri = uri.replacingOccurrences(of: "nostr:", with: "")
|
uri = uri.replacingOccurrences(of: "nostr:", with: "")
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class RelayConnection: WebSocketDelegate {
|
|||||||
self.connect(force: true)
|
self.connect(force: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func connect(force: Bool = false){
|
func connect(force: Bool = false){
|
||||||
if !force && (self.isConnected || self.isConnecting) {
|
if !force && (self.isConnected || self.isConnecting) {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -28,9 +28,20 @@ struct RelayHandler {
|
|||||||
let callback: (String, NostrConnectionEvent) -> ()
|
let callback: (String, NostrConnectionEvent) -> ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct QueuedRequest {
|
||||||
|
let req: NostrRequest
|
||||||
|
let relay: String
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NostrRequestId: Equatable, Hashable {
|
||||||
|
let relay: String?
|
||||||
|
let sub_id: String
|
||||||
|
}
|
||||||
|
|
||||||
class RelayPool {
|
class RelayPool {
|
||||||
var relays: [Relay] = []
|
var relays: [Relay] = []
|
||||||
var handlers: [RelayHandler] = []
|
var handlers: [RelayHandler] = []
|
||||||
|
var request_queue: [QueuedRequest] = []
|
||||||
|
|
||||||
var descriptors: [RelayDescriptor] {
|
var descriptors: [RelayDescriptor] {
|
||||||
relays.map { $0.descriptor }
|
relays.map { $0.descriptor }
|
||||||
@@ -148,13 +159,38 @@ class RelayPool {
|
|||||||
send(.subscribe(.init(filters: filters, sub_id: sub_id)), to: to)
|
send(.subscribe(.init(filters: filters, sub_id: sub_id)), to: to)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func count_queued(relay: String) -> Int {
|
||||||
|
var c = 0
|
||||||
|
for request in request_queue {
|
||||||
|
if request.relay == relay {
|
||||||
|
c += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func queue_req(r: NostrRequest, relay: String) {
|
||||||
|
let count = count_queued(relay: relay)
|
||||||
|
guard count <= 10 else {
|
||||||
|
print("can't queue, too many queued events for \(relay)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
print("queueing request: \(r) for \(relay)")
|
||||||
|
request_queue.append(QueuedRequest(req: r, relay: relay))
|
||||||
|
}
|
||||||
|
|
||||||
func send(_ req: NostrRequest, to: [String]? = nil) {
|
func send(_ req: NostrRequest, to: [String]? = nil) {
|
||||||
let relays = to.map{ get_relays($0) } ?? self.relays
|
let relays = to.map{ get_relays($0) } ?? self.relays
|
||||||
|
|
||||||
for relay in relays {
|
for relay in relays {
|
||||||
if relay.connection.isConnected {
|
guard relay.connection.isConnected else {
|
||||||
relay.connection.send(req)
|
queue_req(r: req, relay: relay.id)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
relay.connection.send(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,9 +229,28 @@ class RelayPool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func run_queue(_ relay_id: String) {
|
||||||
|
self.request_queue = request_queue.reduce(into: Array<QueuedRequest>()) { (q, req) in
|
||||||
|
guard req.relay == relay_id else {
|
||||||
|
q.append(req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
print("running queueing request: \(req.req) for \(relay_id)")
|
||||||
|
self.send(req.req, to: [relay_id])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func handle_event(relay_id: String, event: NostrConnectionEvent) {
|
func handle_event(relay_id: String, event: NostrConnectionEvent) {
|
||||||
record_last_pong(relay_id: relay_id, event: event)
|
record_last_pong(relay_id: relay_id, event: event)
|
||||||
|
|
||||||
|
// run req queue when we reconnect
|
||||||
|
if case .ws_event(let ws) = event {
|
||||||
|
if case .connected = ws {
|
||||||
|
run_queue(relay_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// handle reconnect logic, etc?
|
// handle reconnect logic, etc?
|
||||||
for handler in handlers {
|
for handler in handlers {
|
||||||
handler.callback(relay_id, event)
|
handler.callback(relay_id, event)
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ struct EventActionBar: View {
|
|||||||
let generator = UIImpactFeedbackGenerator(style: .medium)
|
let generator = UIImpactFeedbackGenerator(style: .medium)
|
||||||
@State var sheet: ActionBarSheet? = nil
|
@State var sheet: ActionBarSheet? = nil
|
||||||
@State var confirm_boost: Bool = false
|
@State var confirm_boost: Bool = false
|
||||||
|
@State var show_share_sheet: Bool = false
|
||||||
@StateObject var bar: ActionBarModel
|
@StateObject var bar: ActionBarModel
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@@ -40,6 +41,7 @@ struct EventActionBar: View {
|
|||||||
EventActionButton(img: "bubble.left", col: nil) {
|
EventActionButton(img: "bubble.left", col: nil) {
|
||||||
notify(.reply, event)
|
notify(.reply, event)
|
||||||
}
|
}
|
||||||
|
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
|
||||||
}
|
}
|
||||||
|
|
||||||
HStack(alignment: .bottom) {
|
HStack(alignment: .bottom) {
|
||||||
@@ -55,6 +57,7 @@ struct EventActionBar: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
|
||||||
|
|
||||||
HStack(alignment: .bottom) {
|
HStack(alignment: .bottom) {
|
||||||
Text("\(bar.likes > 0 ? "\(bar.likes)" : "")")
|
Text("\(bar.likes > 0 ? "\(bar.likes)" : "")")
|
||||||
@@ -69,6 +72,12 @@ struct EventActionBar: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
|
||||||
|
|
||||||
|
EventActionButton(img: "square.and.arrow.up", col: Color.gray) {
|
||||||
|
show_share_sheet = true
|
||||||
|
}
|
||||||
|
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
HStack(alignment: .bottom) {
|
HStack(alignment: .bottom) {
|
||||||
@@ -86,6 +95,13 @@ struct EventActionBar: View {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
.sheet(isPresented: $show_share_sheet) {
|
||||||
|
if let note_id = bech32_note_id(event.id) {
|
||||||
|
if let url = URL(string: "https://damus.io/" + note_id) {
|
||||||
|
ShareSheet(activityItems: [url])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.alert("Boost", isPresented: $confirm_boost) {
|
.alert("Boost", isPresented: $confirm_boost) {
|
||||||
Button("Cancel") {
|
Button("Cancel") {
|
||||||
confirm_boost = false
|
confirm_boost = false
|
||||||
@@ -142,7 +158,6 @@ func EventActionButton(img: String, col: Color?, action: @escaping () -> ()) ->
|
|||||||
.font(.footnote.weight(.medium))
|
.font(.footnote.weight(.medium))
|
||||||
.foregroundColor(col == nil ? Color.gray : col!)
|
.foregroundColor(col == nil ? Color.gray : col!)
|
||||||
}
|
}
|
||||||
.padding(.trailing, 40)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LikeButton: View {
|
struct LikeButton: View {
|
||||||
|
|||||||
@@ -51,7 +51,9 @@ struct InnerProfilePicView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Group {
|
ZStack {
|
||||||
|
Color(uiColor: .systemBackground)
|
||||||
|
|
||||||
KFAnimatedImage(url)
|
KFAnimatedImage(url)
|
||||||
.callbackQueue(.dispatch(.global(qos: .background)))
|
.callbackQueue(.dispatch(.global(qos: .background)))
|
||||||
.processingQueue(.dispatch(.global(qos: .background)))
|
.processingQueue(.dispatch(.global(qos: .background)))
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ struct ProfileView: View {
|
|||||||
@State private var showingEditProfile = false
|
@State private var showingEditProfile = false
|
||||||
@State var showing_select_wallet: Bool = false
|
@State var showing_select_wallet: Bool = false
|
||||||
@State var is_zoomed: Bool = false
|
@State var is_zoomed: Bool = false
|
||||||
|
@State var show_share_sheet: Bool = false
|
||||||
@StateObject var user_settings = UserSettingsStore()
|
@StateObject var user_settings = UserSettingsStore()
|
||||||
|
|
||||||
@Environment(\.dismiss) var dismiss
|
@Environment(\.dismiss) var dismiss
|
||||||
@@ -165,7 +166,19 @@ struct ProfileView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static let markdown = Markdown()
|
static let markdown = Markdown()
|
||||||
|
|
||||||
|
var ShareButton: some View {
|
||||||
|
Button(action: {
|
||||||
|
show_share_sheet = true
|
||||||
|
}) {
|
||||||
|
Image(systemName: "square.and.arrow.up.circle.fill")
|
||||||
|
.symbolRenderingMode(.palette)
|
||||||
|
.font(.system(size: 32))
|
||||||
|
.padding()
|
||||||
|
.foregroundStyle(.white, .black, .black.opacity(0.8))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var DMButton: some View {
|
var DMButton: some View {
|
||||||
let dm_model = damus_state.dms.lookup_or_create(profile.pubkey)
|
let dm_model = damus_state.dms.lookup_or_create(profile.pubkey)
|
||||||
let dmview = DMChatView(damus_state: damus_state, pubkey: profile.pubkey)
|
let dmview = DMChatView(damus_state: damus_state, pubkey: profile.pubkey)
|
||||||
@@ -186,6 +199,9 @@ struct ProfileView: View {
|
|||||||
.aspectRatio(contentMode: .fill)
|
.aspectRatio(contentMode: .fill)
|
||||||
.frame(width: geo.size.width, height: 150)
|
.frame(width: geo.size.width, height: 150)
|
||||||
.clipped()
|
.clipped()
|
||||||
|
|
||||||
|
ShareButton
|
||||||
|
.offset(x: geo.size.width - 80.0, y: 50.0 )
|
||||||
}
|
}
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
let data = damus_state.profiles.lookup(id: profile.pubkey)
|
let data = damus_state.profiles.lookup(id: profile.pubkey)
|
||||||
@@ -200,7 +216,7 @@ struct ProfileView: View {
|
|||||||
ProfilePicView(pubkey: profile.pubkey, size: zoom_size, highlight: .none, profiles: damus_state.profiles)
|
ProfilePicView(pubkey: profile.pubkey, size: zoom_size, highlight: .none, profiles: damus_state.profiles)
|
||||||
}
|
}
|
||||||
.offset(y: -(pfp_size/2.0)) // Increase if set a frame
|
.offset(y: -(pfp_size/2.0)) // Increase if set a frame
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Group {
|
Group {
|
||||||
@@ -223,10 +239,12 @@ struct ProfileView: View {
|
|||||||
EditButton(damus_state: damus_state)
|
EditButton(damus_state: damus_state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
.offset(y: -15.0) // Increase if set a frame
|
.offset(y: -15.0) // Increase if set a frame
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfileNameView(pubkey: profile.pubkey, profile: data, damus: damus_state)
|
ProfileNameView(pubkey: profile.pubkey, profile: data, damus: damus_state)
|
||||||
//.padding(.bottom)
|
//.padding(.bottom)
|
||||||
.padding(.top,-(pfp_size/2.0))
|
.padding(.top,-(pfp_size/2.0))
|
||||||
@@ -324,6 +342,13 @@ struct ProfileView: View {
|
|||||||
followers.unsubscribe()
|
followers.unsubscribe()
|
||||||
// our profilemodel needs a bit more help
|
// our profilemodel needs a bit more help
|
||||||
}
|
}
|
||||||
|
.sheet(isPresented: $show_share_sheet) {
|
||||||
|
if let npub = bech32_pubkey(profile.pubkey) {
|
||||||
|
if let url = URL(string: "https://damus.io/" + npub) {
|
||||||
|
ShareSheet(activityItems: [url])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -380,15 +405,11 @@ struct KeyView: View {
|
|||||||
isCopied = false
|
isCopied = false
|
||||||
}
|
}
|
||||||
} label: {
|
} label: {
|
||||||
Label {
|
Label("Public Key", systemImage: "key.fill")
|
||||||
Text("Public key")
|
.font(.custom("key", size: 12.0))
|
||||||
} icon: {
|
.labelStyle(IconOnlyLabelStyle())
|
||||||
Image("ic-key")
|
.foregroundStyle(hex_to_rgb(pubkey))
|
||||||
.contentShape(Rectangle())
|
.symbolRenderingMode(.palette)
|
||||||
.frame(width: 16, height: 16)
|
|
||||||
}
|
|
||||||
.labelStyle(IconOnlyLabelStyle())
|
|
||||||
.symbolRenderingMode(.hierarchical)
|
|
||||||
}
|
}
|
||||||
.padding(.leading,4)
|
.padding(.leading,4)
|
||||||
Text(abbrev_pubkey(bech32, amount: 16))
|
Text(abbrev_pubkey(bech32, amount: 16))
|
||||||
|
|||||||
@@ -4,6 +4,10 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>aps-environment</key>
|
<key>aps-environment</key>
|
||||||
<string>development</string>
|
<string>development</string>
|
||||||
|
<key>com.apple.developer.associated-domains</key>
|
||||||
|
<array>
|
||||||
|
<string>applinks:damus.io</string>
|
||||||
|
</array>
|
||||||
<key>keychain-access-groups</key>
|
<key>keychain-access-groups</key>
|
||||||
<array>
|
<array>
|
||||||
<string>$(AppIdentifierPrefix)com.jb55.damus2</string>
|
<string>$(AppIdentifierPrefix)com.jb55.damus2</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user