Convert more NavigationLinks to router

This commit is contained in:
Scott Penrose
2023-05-26 16:58:24 -04:00
committed by William Casarin
parent f0b0eade37
commit 242455410e
19 changed files with 274 additions and 193 deletions

View File

@@ -11,21 +11,10 @@ struct UserViewRow: View {
let damus_state: DamusState let damus_state: DamusState
let pubkey: String let pubkey: String
@State var navigating: Bool = false
var body: some View { var body: some View {
let dest = ProfileView(damus_state: damus_state, pubkey: pubkey)
UserView(damus_state: damus_state, pubkey: pubkey) UserView(damus_state: damus_state, pubkey: pubkey)
.contentShape(Rectangle()) .contentShape(Rectangle())
.background( .background(.clear)
NavigationLink(destination: dest, isActive: $navigating) {
EmptyView()
}
)
.onTapGesture {
navigating = true
}
} }
} }

View File

@@ -329,7 +329,7 @@ struct ContentView: View {
SideMenuView(damus_state: damus, isSidebarVisible: $isSideBarOpened.animation()) SideMenuView(damus_state: damus, isSidebarVisible: $isSideBarOpened.animation())
) )
.navigationDestination(for: Route.self) { route in .navigationDestination(for: Route.self) { route in
route.view(navigationCordinator: navigationCoordinator) route.view(navigationCordinator: navigationCoordinator, damusState: damus_state!)
} }
.onReceive(handle_notify(.switched_timeline)) { _ in .onReceive(handle_notify(.switched_timeline)) { _ in
navigationCoordinator.popToRoot() navigationCoordinator.popToRoot()

View File

@@ -8,71 +8,131 @@
import SwiftUI import SwiftUI
enum Route: Hashable { enum Route: Hashable {
case Profile(damusSate: DamusState, profile: ProfileModel, followers: FollowersModel) case ProfileByKey(pubkey: String)
case Followers(damusState: DamusState, environmentObject: FollowersModel) case Profile(profile: ProfileModel, followers: FollowersModel)
case Relay(damusState: DamusState, relay: String, showActionButtons: Binding<Bool>) case Followers(environmentObject: FollowersModel)
case Following(damusState: DamusState, following: FollowingModel) case Relay(relay: String, showActionButtons: Binding<Bool>)
case MuteList(damusState: DamusState, users: [String]) case RelayDetail(relay: String, metadata: RelayMetadata)
case RelayConfig(damusState: DamusState) case Following(following: FollowingModel)
case Bookmarks(damusState: DamusState) case MuteList(users: [String])
case Config(damusState: DamusState) case RelayConfig
case EditMetadata(damusState: DamusState) case Bookmarks
case DMChat(damusState: DamusState, dms: DirectMessageModel) case Config
case UserRelays(damusState: DamusState, relays: [String]) case EditMetadata
case DMChat(dms: DirectMessageModel)
case UserRelays(relays: [String])
case KeySettings(keypair: Keypair)
case AppearanceSettings(settings: UserSettingsStore) // Observed object.. is this an issue?
case NotificationSettings(settings: UserSettingsStore) // Observed object.. is this an issue?
case ZapSettings(settings: UserSettingsStore) // Observed object.. is this an issue?
case TranslationSettings(settings: UserSettingsStore) // Observed object.. is this an issue?
case Thread(thread: ThreadModel)
case Reposts(reposts: RepostsModel)
case Reactions(reactions: ReactionsModel)
case Zaps(target: ZapTarget)
case Search(search: SearchModel)
@ViewBuilder @ViewBuilder
func view(navigationCordinator: NavigationCoordinator) -> some View { func view(navigationCordinator: NavigationCoordinator, damusState: DamusState) -> some View {
switch self { switch self {
case .Profile (let damusState, let profile, let followers): case .ProfileByKey(let pubkey):
ProfileView(damus_state: damusState, pubkey: pubkey)
case .Profile(let profile, let followers):
ProfileView(damus_state: damusState, profile: profile, followers: followers) ProfileView(damus_state: damusState, profile: profile, followers: followers)
case .Followers (let damusState, let environmentObject): case .Followers(let environmentObject):
FollowersView(damus_state: damusState) FollowersView(damus_state: damusState)
.environmentObject(environmentObject) .environmentObject(environmentObject)
case .Relay (let damusState, let relay, let showActionButtons): case .Relay(let relay, let showActionButtons):
RelayView(state: damusState, relay: relay, showActionButtons: showActionButtons) RelayView(state: damusState, relay: relay, showActionButtons: showActionButtons)
case .Following(let damusState, let following): case .RelayDetail(let relay, let metadata):
RelayDetailView(state: damusState, relay: relay, nip11: metadata)
case .Following(let following):
FollowingView(damus_state: damusState, following: following) FollowingView(damus_state: damusState, following: following)
case .MuteList(let damusState, let users): case .MuteList(let users):
MutelistView(damus_state: damusState, users: users) MutelistView(damus_state: damusState, users: users)
case .RelayConfig(let damusState): case .RelayConfig:
RelayConfigView(state: damusState) RelayConfigView(state: damusState)
case .Bookmarks(let damusState): case .Bookmarks:
BookmarksView(state: damusState) BookmarksView(state: damusState)
case .Config(let damusState): case .Config:
ConfigView(state: damusState) ConfigView(state: damusState)
case .EditMetadata(let damusState): case .EditMetadata:
EditMetadataView(damus_state: damusState) EditMetadataView(damus_state: damusState)
case .DMChat(let damusState, let dms): case .DMChat(let dms):
DMChatView(damus_state: damusState, dms: dms) DMChatView(damus_state: damusState, dms: dms)
case .UserRelays(let damusState, let relays): case .UserRelays(let relays):
UserRelaysView(state: damusState, relays: relays) UserRelaysView(state: damusState, relays: relays)
case .KeySettings(let keypair):
KeySettingsView(keypair: keypair)
case .AppearanceSettings(let settings):
AppearanceSettingsView(settings: settings)
case .NotificationSettings(let settings):
NotificationSettingsView(settings: settings)
case .ZapSettings(let settings):
ZapSettingsView(settings: settings)
case .TranslationSettings(let settings):
NotificationSettingsView(settings: settings)
case .Thread(let thread):
ThreadView(state: damusState, thread: thread)
case .Reposts(let reposts):
RepostsView(damus_state: damusState, model: reposts)
case .Reactions(let reactions):
ReactionsView(damus_state: damusState, model: reactions)
case .Zaps(let target):
ZapsView(state: damusState, target: target)
case .Search(let search):
SearchView(appstate: damusState, search: search)
} }
} }
static func == (lhs: Route, rhs: Route) -> Bool { static func == (lhs: Route, rhs: Route) -> Bool {
switch (lhs, rhs) { switch (lhs, rhs) {
case (.Profile (_, let lhs_profile, _), .Profile(_, let rhs_profile, _)): case (.ProfileByKey (let lhs_pubkey), .ProfileByKey(let rhs_pubkey)):
return lhs_pubkey == rhs_pubkey
case (.Profile (let lhs_profile, _), .Profile(let rhs_profile, _)):
return lhs_profile == rhs_profile return lhs_profile == rhs_profile
case (.Followers (_, _), .Followers (_, _)): case (.Followers (_), .Followers (_)):
return true return true
case (.Relay (_, let lhs_relay, _), .Relay (_, let rhs_relay, _)): case (.Relay (let lhs_relay, _), .Relay (let rhs_relay, _)):
return lhs_relay == rhs_relay return lhs_relay == rhs_relay
case (.Following(_, _), .Following(_, _)): case (.RelayDetail(let lhs_relay, _), .RelayDetail(let rhs_relay, _)):
return lhs_relay == rhs_relay
case (.Following(_), .Following(_)):
return true return true
case (.MuteList(_, let lhs_users), .MuteList(_, let rhs_users)): case (.MuteList(let lhs_users), .MuteList(let rhs_users)):
return lhs_users == rhs_users return lhs_users == rhs_users
case (.RelayConfig(_), .RelayConfig(_)): case (.RelayConfig, .RelayConfig):
return true return true
case (.Bookmarks(_), .Bookmarks(_)): case (.Bookmarks, .Bookmarks):
return true return true
case (.Config(_), .Config(_)): case (.Config, .Config):
return true return true
case (.EditMetadata(_), .EditMetadata(_)): case (.EditMetadata, .EditMetadata):
return true return true
case (.DMChat(_, let lhs_dms), .DMChat(_, let rhs_dms)): case (.DMChat(let lhs_dms), .DMChat(let rhs_dms)):
return lhs_dms.our_pubkey == rhs_dms.our_pubkey return lhs_dms.our_pubkey == rhs_dms.our_pubkey
case (.UserRelays(_, let lhs_relays), .UserRelays(_, let rhs_relays)): case (.UserRelays(let lhs_relays), .UserRelays(let rhs_relays)):
return lhs_relays == rhs_relays return lhs_relays == rhs_relays
case (.KeySettings(let lhs_keypair), .KeySettings(let rhs_keypair)):
return lhs_keypair.pubkey == rhs_keypair.pubkey
case (.AppearanceSettings(_), .AppearanceSettings(_)):
return true
case (.NotificationSettings(_), .NotificationSettings(_)):
return true
case (.ZapSettings(_), .ZapSettings(_)):
return true
case (.TranslationSettings(_), .TranslationSettings(_)):
return true
case (.Thread(let lhs_threadModel), .Thread(thread: let rhs_threadModel)):
return lhs_threadModel.event.id == rhs_threadModel.event.id
case (.Reposts(let lhs_reposts), .Reposts(let rhs_reposts)):
return lhs_reposts.target == rhs_reposts.target
case (.Reactions(let lhs_reactions), .Reactions(let rhs_reactions)):
return lhs_reactions.target == rhs_reactions.target
case (.Zaps(let lhs_target), .Zaps(let rhs_target)):
return lhs_target == rhs_target
case (.Search(let lhs_search), .Search(let rhs_search)):
return lhs_search.sub_id == rhs_search.sub_id && lhs_search.profiles_subid == rhs_search.profiles_subid
default: default:
return false return false
} }
@@ -80,28 +140,67 @@ enum Route: Hashable {
func hash(into hasher: inout Hasher) { func hash(into hasher: inout Hasher) {
switch self { switch self {
case .Profile(_, let profile, _): case .ProfileByKey(let pubkey):
hasher.combine("profilebykey")
hasher.combine(pubkey)
case .Profile(let profile, _):
hasher.combine("profile")
hasher.combine(profile.pubkey) hasher.combine(profile.pubkey)
case .Followers(_, _): case .Followers(_):
hasher.combine("followers") hasher.combine("followers")
case .Relay(_, let relay, _): case .Relay(let relay, _):
hasher.combine("relay")
hasher.combine(relay) hasher.combine(relay)
case .Following(_, _): case .RelayDetail(let relay, _):
hasher.combine("relayDetail")
hasher.combine(relay)
case .Following(_):
hasher.combine("following") hasher.combine("following")
case .MuteList(_, let users): case .MuteList(let users):
hasher.combine("muteList")
hasher.combine(users) hasher.combine(users)
case .RelayConfig(_): case .RelayConfig:
hasher.combine("relayConfig") hasher.combine("relayConfig")
case .Bookmarks(_): case .Bookmarks:
hasher.combine("bookmarks") hasher.combine("bookmarks")
case .Config(_): case .Config:
hasher.combine("config") hasher.combine("config")
case .EditMetadata(_): case .EditMetadata:
hasher.combine("editMetadata") hasher.combine("editMetadata")
case .DMChat(_, let dms): case .DMChat(let dms):
hasher.combine("dms")
hasher.combine(dms.our_pubkey) hasher.combine(dms.our_pubkey)
case .UserRelays(_, let relays): case .UserRelays(let relays):
hasher.combine("userRelays")
hasher.combine(relays) hasher.combine(relays)
case .KeySettings(let keypair):
hasher.combine("keySettings")
hasher.combine(keypair.pubkey)
case .AppearanceSettings(_):
hasher.combine("appearanceSettings")
case .NotificationSettings(_):
hasher.combine("notificationSettings")
case .ZapSettings(_):
hasher.combine("zapSettings")
case .TranslationSettings(_):
hasher.combine("translationSettings")
case .Thread(let threadModel):
hasher.combine("thread")
hasher.combine(threadModel.event.id)
case .Reposts(let reposts):
hasher.combine("reposts")
hasher.combine(reposts.target)
case .Zaps(let target):
hasher.combine("zaps")
hasher.combine(target.id)
hasher.combine(target.pubkey)
case .Reactions(let reactions):
hasher.combine("reactions")
hasher.combine(reactions.target)
case .Search(let search):
hasher.combine("search")
hasher.combine(search.sub_id)
hasher.combine(search.profiles_subid)
} }
} }
} }

View File

@@ -25,7 +25,7 @@ struct EventDetailBar: View {
var body: some View { var body: some View {
HStack { HStack {
if bar.boosts > 0 { if bar.boosts > 0 {
NavigationLink(destination: RepostsView(damus_state: state, model: RepostsModel(state: state, target: target))) { NavigationLink(value: Route.Reposts(reposts: RepostsModel(state: state, target: target))) {
let noun = Text(verbatim: repostsCountString(bar.boosts)).foregroundColor(.gray) let noun = Text(verbatim: repostsCountString(bar.boosts)).foregroundColor(.gray)
Text("\(Text(verbatim: bar.boosts.formatted()).font(.body.bold())) \(noun)", comment: "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'.") Text("\(Text(verbatim: bar.boosts.formatted()).font(.body.bold())) \(noun)", comment: "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'.")
} }
@@ -33,7 +33,7 @@ struct EventDetailBar: View {
} }
if bar.likes > 0 && !state.settings.onlyzaps_mode { if bar.likes > 0 && !state.settings.onlyzaps_mode {
NavigationLink(destination: ReactionsView(damus_state: state, model: ReactionsModel(state: state, target: target))) { NavigationLink(value: Route.Reactions(reactions: ReactionsModel(state: state, target: target))) {
let noun = Text(verbatim: reactionsCountString(bar.likes)).foregroundColor(.gray) let noun = Text(verbatim: reactionsCountString(bar.likes)).foregroundColor(.gray)
Text("\(Text(verbatim: bar.likes.formatted()).font(.body.bold())) \(noun)", comment: "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'.") Text("\(Text(verbatim: bar.likes.formatted()).font(.body.bold())) \(noun)", comment: "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'.")
} }
@@ -41,8 +41,7 @@ struct EventDetailBar: View {
} }
if bar.zaps > 0 { if bar.zaps > 0 {
let dst = ZapsView(state: state, target: .note(id: target, author: target_pk)) NavigationLink(value: Route.Zaps(target: .note(id: target, author: target_pk))) {
NavigationLink(destination: dst) {
let noun = Text(verbatim: zapsCountString(bar.zaps)).foregroundColor(.gray) let noun = Text(verbatim: zapsCountString(bar.zaps)).foregroundColor(.gray)
Text("\(Text(verbatim: bar.zaps.formatted()).font(.body.bold())) \(noun)", comment: "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'.") Text("\(Text(verbatim: bar.zaps.formatted()).font(.body.bold())) \(noun)", comment: "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'.")
} }

View File

@@ -18,16 +18,16 @@ struct ConfigView: View {
@State var delete_account_warning: Bool = false @State var delete_account_warning: Bool = false
@State var confirm_delete_account: Bool = false @State var confirm_delete_account: Bool = false
@State var delete_text: String = "" @State var delete_text: String = ""
@ObservedObject var settings: UserSettingsStore @ObservedObject var settings: UserSettingsStore
private let DELETE_KEYWORD = "DELETE" private let DELETE_KEYWORD = "DELETE"
init(state: DamusState) { init(state: DamusState) {
self.state = state self.state = state
_settings = ObservedObject(initialValue: state.settings) _settings = ObservedObject(initialValue: state.settings)
} }
func textColor() -> Color { func textColor() -> Color {
colorScheme == .light ? DamusColors.black : DamusColors.white colorScheme == .light ? DamusColors.black : DamusColors.white
} }
@@ -36,31 +36,30 @@ struct ConfigView: View {
ZStack(alignment: .leading) { ZStack(alignment: .leading) {
Form { Form {
Section { Section {
NavigationLink(destination: KeySettingsView(keypair: state.keypair)) { NavigationLink(value: Route.KeySettings(keypair: state.keypair)) {
IconLabel(NSLocalizedString("Keys", comment: "Settings section for managing keys"), img_name: "key", color: .purple) IconLabel(NSLocalizedString("Keys", comment: "Settings section for managing keys"), img_name: "key", color: .purple)
} }
NavigationLink(destination: AppearanceSettingsView(settings: settings)) { NavigationLink(value: Route.AppearanceSettings(settings: settings)) {
IconLabel(NSLocalizedString("Appearance", comment: "Section header for text and appearance settings"), img_name: "eye", color: .red) IconLabel(NSLocalizedString("Appearance", comment: "Section header for text and appearance settings"), img_name: "eye", color: .red)
} }
NavigationLink(destination: SearchSettingsView(settings: settings)) { NavigationLink(destination: SearchSettingsView(settings: settings)) {
IconLabel(NSLocalizedString("Search/Universe", comment: "Section header for search/universe settings"), img_name: "magnifyingglass", color: .red) IconLabel(NSLocalizedString("Search/Universe", comment: "Section header for search/universe settings"), img_name: "magnifyingglass", color: .red)
} }
NavigationLink(destination: NotificationSettingsView(settings: settings)) { NavigationLink(value: Route.NotificationSettings(settings: settings)) {
IconLabel(NSLocalizedString("Notifications", comment: "Section header for Damus notifications"), img_name: "notification-bell-on", color: .blue) IconLabel(NSLocalizedString("Notifications", comment: "Section header for Damus notifications"), img_name: "notification-bell-on", color: .blue)
} }
NavigationLink(destination: ZapSettingsView(settings: settings)) { NavigationLink(value: Route.ZapSettings(settings: settings)) {
IconLabel(NSLocalizedString("Zaps", comment: "Section header for zap settings"), img_name: "zap.fill", color: .orange) IconLabel(NSLocalizedString("Zaps", comment: "Section header for zap settings"), img_name: "zap.fill", color: .orange)
} }
NavigationLink(destination: TranslationSettingsView(settings: settings)) { NavigationLink(value: Route.TranslationSettings(settings: settings)) {
IconLabel(NSLocalizedString("Translation", comment: "Section header for text and appearance settings"), img_name: "globe", color: .green) IconLabel(NSLocalizedString("Translation", comment: "Section header for text and appearance settings"), img_name: "globe", color: .green)
} }
} }
Section(NSLocalizedString("Sign Out", comment: "Section title for signing out")) { Section(NSLocalizedString("Sign Out", comment: "Section title for signing out")) {
Button(action: { Button(action: {
@@ -116,11 +115,11 @@ struct ConfigView: View {
guard let full_kp = state.keypair.to_full() else { guard let full_kp = state.keypair.to_full() else {
return return
} }
guard delete_text == DELETE_KEYWORD else { guard delete_text == DELETE_KEYWORD else {
return return
} }
let ev = created_deleted_account_profile(keypair: full_kp) let ev = created_deleted_account_profile(keypair: full_kp)
state.postbox.send(ev) state.postbox.send(ev)
notify(.logout, ()) notify(.logout, ())
@@ -164,7 +163,7 @@ func handle_string_amount(new_value: String) -> Int? {
guard let amt = NumberFormatter().number(from: filtered) as? Int else { guard let amt = NumberFormatter().number(from: filtered) as? Int else {
return nil return nil
} }
return amt return amt
} }

View File

@@ -61,8 +61,7 @@ struct DMChatView: View, KeyboardReadable {
var Header: some View { var Header: some View {
let profile = damus_state.profiles.lookup(id: pubkey) let profile = damus_state.profiles.lookup(id: pubkey)
let profile_page = ProfileView(damus_state: damus_state, pubkey: pubkey) return NavigationLink(value: Route.ProfileByKey(pubkey: pubkey)) {
return NavigationLink(destination: profile_page) {
HStack { HStack {
ProfilePicView(pubkey: pubkey, size: 24, highlight: .none, profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation) ProfilePicView(pubkey: pubkey, size: 24, highlight: .none, profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)

View File

@@ -72,8 +72,7 @@ struct BuilderEventView: View {
if let event { if let event {
let ev = event.get_inner_event(cache: damus.events) ?? event let ev = event.get_inner_event(cache: damus.events) ?? event
let thread = ThreadModel(event: ev, damus_state: damus) let thread = ThreadModel(event: ev, damus_state: damus)
let dest = ThreadView(state: damus, thread: thread) NavigationLink(value: Route.Thread(thread: thread)) {
NavigationLink(destination: dest) {
EventView(damus: damus, event: event, options: .embedded) EventView(damus: damus, event: event, options: .embedded)
.padding([.top, .bottom], 8) .padding([.top, .bottom], 8)
}.buttonStyle(.plain) }.buttonStyle(.plain)

View File

@@ -37,7 +37,7 @@ struct EventProfile: View {
var body: some View { var body: some View {
HStack(alignment: .center) { HStack(alignment: .center) {
VStack { VStack {
NavigationLink(destination: ProfileView(damus_state: damus_state, pubkey: pubkey)) { NavigationLink(value: Route.ProfileByKey(pubkey: pubkey)) {
ProfilePicView(pubkey: pubkey, size: pfp_size, highlight: .none, profiles: damus_state.profiles, disable_animation: disable_animation) ProfilePicView(pubkey: pubkey, size: pfp_size, highlight: .none, profiles: damus_state.profiles, disable_animation: disable_animation)
} }
} }

View File

@@ -240,8 +240,7 @@ struct EventGroupView: View {
if let event { if let event {
let thread = ThreadModel(event: event, damus_state: state) let thread = ThreadModel(event: event, damus_state: state)
let dest = ThreadView(state: state, thread: thread) NavigationLink(value: Route.Thread(thread: thread)) {
NavigationLink(destination: dest) {
VStack(alignment: .leading) { VStack(alignment: .leading) {
GroupDescription(unique_pubkeys) GroupDescription(unique_pubkeys)
EventBody(damus_state: state, event: event, size: .normal, options: [.truncate_content]) EventBody(damus_state: state, event: event, size: .normal, options: [.truncate_content])

View File

@@ -59,7 +59,7 @@ struct NotificationItemView: View {
EventGroupView(state: state, event: ev, group: .reaction(evgrp)) EventGroupView(state: state, event: ev, group: .reaction(evgrp))
case .reply(let ev): case .reply(let ev):
NavigationLink(destination: ThreadView(state: state, thread: ThreadModel(event: ev, damus_state: state))) { NavigationLink(value: Route.Thread(thread: ThreadModel(event: ev, damus_state: state))) {
EventView(damus: state, event: ev, options: options) EventView(damus: state, event: ev, options: options)
} }
.buttonStyle(.plain) .buttonStyle(.plain)

View File

@@ -28,7 +28,7 @@ struct MaybeAnonPfpView: View {
.font(.largeTitle) .font(.largeTitle)
.frame(width: size, height: size) .frame(width: size, height: size)
} else { } else {
NavigationLink(destination: ProfileView(damus_state: state, pubkey: pubkey)) { NavigationLink(value: Route.ProfileByKey(pubkey: pubkey)) {
ProfilePicView(pubkey: pubkey, size: size, highlight: .none, profiles: state.profiles, disable_animation: state.settings.disable_animation) ProfilePicView(pubkey: pubkey, size: size, highlight: .none, profiles: state.profiles, disable_animation: state.settings.disable_animation)
} }
} }

View File

@@ -73,11 +73,11 @@ func followedByString(_ friend_intersection: [String], profiles: Profiles, local
struct EditButton: View { struct EditButton: View {
let damus_state: DamusState let damus_state: DamusState
@Environment(\.colorScheme) var colorScheme @Environment(\.colorScheme) var colorScheme
var body: some View { var body: some View {
NavigationLink(value: Route.EditMetadata(damusState: damus_state)) { NavigationLink(value: Route.EditMetadata) {
Text("Edit", comment: "Button to edit user's profile.") Text("Edit", comment: "Button to edit user's profile.")
.frame(height: 30) .frame(height: 30)
.padding(.horizontal,25) .padding(.horizontal,25)
@@ -92,11 +92,11 @@ struct EditButton: View {
.lineLimit(1) .lineLimit(1)
} }
} }
func fillColor() -> Color { func fillColor() -> Color {
colorScheme == .light ? DamusColors.black : DamusColors.white colorScheme == .light ? DamusColors.black : DamusColors.white
} }
func borderColor() -> Color { func borderColor() -> Color {
colorScheme == .light ? DamusColors.black : DamusColors.white colorScheme == .light ? DamusColors.black : DamusColors.white
} }
@@ -104,11 +104,11 @@ struct EditButton: View {
struct VisualEffectView: UIViewRepresentable { struct VisualEffectView: UIViewRepresentable {
var effect: UIVisualEffect? var effect: UIVisualEffect?
func makeUIView(context: UIViewRepresentableContext<Self>) -> UIVisualEffectView { func makeUIView(context: UIViewRepresentableContext<Self>) -> UIVisualEffectView {
UIVisualEffectView() UIVisualEffectView()
} }
func updateUIView(_ uiView: UIVisualEffectView, context: UIViewRepresentableContext<Self>) { func updateUIView(_ uiView: UIVisualEffectView, context: UIViewRepresentableContext<Self>) {
uiView.effect = effect uiView.effect = effect
} }
@@ -120,52 +120,52 @@ struct ProfileView: View {
let bannerHeight: CGFloat = 150.0 let bannerHeight: CGFloat = 150.0
static let markdown = Markdown() static let markdown = Markdown()
@State var is_zoomed: Bool = false @State var is_zoomed: Bool = false
@State var show_share_sheet: Bool = false @State var show_share_sheet: Bool = false
@State var show_qr_code: Bool = false @State var show_qr_code: Bool = false
@State var action_sheet_presented: Bool = false @State var action_sheet_presented: Bool = false
@State var filter_state : FilterState = .posts @State var filter_state : FilterState = .posts
@State var yOffset: CGFloat = 0 @State var yOffset: CGFloat = 0
@StateObject var profile: ProfileModel @StateObject var profile: ProfileModel
@StateObject var followers: FollowersModel @StateObject var followers: FollowersModel
@StateObject var zap_button_model: ZapButtonModel = ZapButtonModel() @StateObject var zap_button_model: ZapButtonModel = ZapButtonModel()
init(damus_state: DamusState, profile: ProfileModel, followers: FollowersModel) { init(damus_state: DamusState, profile: ProfileModel, followers: FollowersModel) {
self.damus_state = damus_state self.damus_state = damus_state
self._profile = StateObject(wrappedValue: profile) self._profile = StateObject(wrappedValue: profile)
self._followers = StateObject(wrappedValue: followers) self._followers = StateObject(wrappedValue: followers)
} }
init(damus_state: DamusState, pubkey: String) { init(damus_state: DamusState, pubkey: String) {
self.damus_state = damus_state self.damus_state = damus_state
self._profile = StateObject(wrappedValue: ProfileModel(pubkey: pubkey, damus: damus_state)) self._profile = StateObject(wrappedValue: ProfileModel(pubkey: pubkey, damus: damus_state))
self._followers = StateObject(wrappedValue: FollowersModel(damus_state: damus_state, target: pubkey)) self._followers = StateObject(wrappedValue: FollowersModel(damus_state: damus_state, target: pubkey))
} }
@Environment(\.dismiss) var dismiss @Environment(\.dismiss) var dismiss
@Environment(\.colorScheme) var colorScheme @Environment(\.colorScheme) var colorScheme
@Environment(\.presentationMode) var presentationMode @Environment(\.presentationMode) var presentationMode
func imageBorderColor() -> Color { func imageBorderColor() -> Color {
colorScheme == .light ? DamusColors.white : DamusColors.black colorScheme == .light ? DamusColors.white : DamusColors.black
} }
func bannerBlurViewOpacity() -> Double { func bannerBlurViewOpacity() -> Double {
let progress = -(yOffset + navbarHeight) / 100 let progress = -(yOffset + navbarHeight) / 100
return Double(-yOffset > navbarHeight ? progress : 0) return Double(-yOffset > navbarHeight ? progress : 0)
} }
var bannerSection: some View { var bannerSection: some View {
GeometryReader { proxy -> AnyView in GeometryReader { proxy -> AnyView in
let minY = proxy.frame(in: .global).minY let minY = proxy.frame(in: .global).minY
DispatchQueue.main.async { DispatchQueue.main.async {
self.yOffset = minY self.yOffset = minY
} }
return AnyView( return AnyView(
VStack(spacing: 0) { VStack(spacing: 0) {
ZStack { ZStack {
@@ -173,10 +173,10 @@ struct ProfileView: View {
.aspectRatio(contentMode: .fill) .aspectRatio(contentMode: .fill)
.frame(width: proxy.size.width, height: minY > 0 ? bannerHeight + minY : bannerHeight) .frame(width: proxy.size.width, height: minY > 0 ? bannerHeight + minY : bannerHeight)
.clipped() .clipped()
VisualEffectView(effect: UIBlurEffect(style: .systemUltraThinMaterial)).opacity(bannerBlurViewOpacity()) VisualEffectView(effect: UIBlurEffect(style: .systemUltraThinMaterial)).opacity(bannerBlurViewOpacity())
} }
Divider().opacity(bannerBlurViewOpacity()) Divider().opacity(bannerBlurViewOpacity())
} }
.frame(height: minY > 0 ? bannerHeight + minY : nil) .frame(height: minY > 0 ? bannerHeight + minY : nil)
@@ -187,11 +187,11 @@ struct ProfileView: View {
.frame(height: bannerHeight) .frame(height: bannerHeight)
.allowsHitTesting(false) .allowsHitTesting(false)
} }
var navbarHeight: CGFloat { var navbarHeight: CGFloat {
return 100.0 - (Theme.safeAreaInsets?.top ?? 0) return 100.0 - (Theme.safeAreaInsets?.top ?? 0)
} }
@ViewBuilder @ViewBuilder
func navImage(img: String) -> some View { func navImage(img: String) -> some View {
Image(img) Image(img)
@@ -199,7 +199,7 @@ struct ProfileView: View {
.background(Color.black.opacity(0.6)) .background(Color.black.opacity(0.6))
.clipShape(Circle()) .clipShape(Circle())
} }
var navBackButton: some View { var navBackButton: some View {
Button { Button {
presentationMode.wrappedValue.dismiss() presentationMode.wrappedValue.dismiss()
@@ -207,7 +207,7 @@ struct ProfileView: View {
navImage(img: "chevron-left") navImage(img: "chevron-left")
} }
} }
var navActionSheetButton: some View { var navActionSheetButton: some View {
Button(action: { Button(action: {
action_sheet_presented = true action_sheet_presented = true
@@ -218,7 +218,7 @@ struct ProfileView: View {
Button(NSLocalizedString("Share", comment: "Button to share the link to a profile.")) { Button(NSLocalizedString("Share", comment: "Button to share the link to a profile.")) {
show_share_sheet = true show_share_sheet = true
} }
Button(NSLocalizedString("QR Code", comment: "Button to view profile's qr code.")) { Button(NSLocalizedString("QR Code", comment: "Button to view profile's qr code.")) {
show_qr_code = true show_qr_code = true
} }
@@ -238,7 +238,7 @@ struct ProfileView: View {
else { else {
return return
} }
guard let new_ev = remove_from_mutelist(keypair: keypair, prev: mutelist, to_remove: profile.pubkey) else { guard let new_ev = remove_from_mutelist(keypair: keypair, prev: mutelist, to_remove: profile.pubkey) else {
return return
} }
@@ -254,7 +254,7 @@ struct ProfileView: View {
} }
} }
} }
var customNavbar: some View { var customNavbar: some View {
HStack { HStack {
navBackButton navBackButton
@@ -265,7 +265,7 @@ struct ProfileView: View {
.padding(.horizontal) .padding(.horizontal)
.accentColor(DamusColors.white) .accentColor(DamusColors.white)
} }
func lnButton(lnurl: String, profile: Profile) -> some View { func lnButton(lnurl: String, profile: Profile) -> some View {
let button_img = profile.reactions == false ? "zap.fill" : "zap" let button_img = profile.reactions == false ? "zap.fill" : "zap"
return Button(action: { return Button(action: {
@@ -278,7 +278,7 @@ struct ProfileView: View {
if profile.reactions == false { if profile.reactions == false {
Text("OnlyZaps Enabled", comment: "Non-tappable text in context menu that shows up when the zap button on profile is long pressed to indicate that the user has enabled OnlyZaps, meaning that they would like to be only zapped and not accept reactions to their notes.") Text("OnlyZaps Enabled", comment: "Non-tappable text in context menu that shows up when the zap button on profile is long pressed to indicate that the user has enabled OnlyZaps, meaning that they would like to be only zapped and not accept reactions to their notes.")
} }
if let addr = profile.lud16 { if let addr = profile.lud16 {
Button { Button {
UIPasteboard.general.string = addr UIPasteboard.general.string = addr
@@ -293,30 +293,30 @@ struct ProfileView: View {
} }
} }
} }
} }
.cornerRadius(24) .cornerRadius(24)
} }
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)
return NavigationLink(value: Route.DMChat(damusState: damus_state, dms: dm_model)) { return NavigationLink(value: Route.DMChat(dms: dm_model)) {
Image("messages") Image("messages")
.profile_button_style(scheme: colorScheme) .profile_button_style(scheme: colorScheme)
} }
} }
func actionSection(profile_data: Profile?) -> some View { func actionSection(profile_data: Profile?) -> some View {
return Group { return Group {
if let profile = profile_data { if let profile = profile_data {
if let lnurl = profile.lnurl, lnurl != "" { if let lnurl = profile.lnurl, lnurl != "" {
lnButton(lnurl: lnurl, profile: profile) lnButton(lnurl: lnurl, profile: profile)
} }
} }
dmButton dmButton
if profile.pubkey != damus_state.pubkey { if profile.pubkey != damus_state.pubkey {
FollowButtonView( FollowButtonView(
target: profile.get_follow_target(), target: profile.get_follow_target(),
@@ -324,26 +324,26 @@ struct ProfileView: View {
follow_state: damus_state.contacts.follow_state(profile.pubkey) follow_state: damus_state.contacts.follow_state(profile.pubkey)
) )
} else if damus_state.keypair.privkey != nil { } else if damus_state.keypair.privkey != nil {
NavigationLink(value: Route.EditMetadata(damusState: damus_state)) { NavigationLink(value: Route.EditMetadata) {
EditButton(damus_state: damus_state) EditButton(damus_state: damus_state)
} }
} }
} }
} }
func pfpOffset() -> CGFloat { func pfpOffset() -> CGFloat {
let progress = -yOffset / navbarHeight let progress = -yOffset / navbarHeight
let offset = (pfp_size / 4.0) * (progress < 1.0 ? progress : 1) let offset = (pfp_size / 4.0) * (progress < 1.0 ? progress : 1)
return offset > 0 ? offset : 0 return offset > 0 ? offset : 0
} }
func pfpScale() -> CGFloat { func pfpScale() -> CGFloat {
let progress = -yOffset / navbarHeight let progress = -yOffset / navbarHeight
let scale = 1.0 - (0.5 * (progress < 1.0 ? progress : 1)) let scale = 1.0 - (0.5 * (progress < 1.0 ? progress : 1))
return scale < 1 ? scale : 1 return scale < 1 ? scale : 1
} }
func nameSection(profile_data: Profile?) -> some View { func nameSection(profile_data: Profile?) -> some View {
return Group { return Group {
HStack(alignment: .center) { HStack(alignment: .center) {
@@ -357,17 +357,17 @@ struct ProfileView: View {
.fullScreenCover(isPresented: $is_zoomed) { .fullScreenCover(isPresented: $is_zoomed) {
ProfilePicImageView(pubkey: profile.pubkey, profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation) ProfilePicImageView(pubkey: profile.pubkey, profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
} }
Spacer() Spacer()
actionSection(profile_data: profile_data) actionSection(profile_data: profile_data)
} }
let follows_you = profile.pubkey != damus_state.pubkey && profile.follows(pubkey: damus_state.pubkey) let follows_you = profile.pubkey != damus_state.pubkey && profile.follows(pubkey: damus_state.pubkey)
ProfileNameView(pubkey: profile.pubkey, profile: profile_data, follows_you: follows_you, damus: damus_state) ProfileNameView(pubkey: profile.pubkey, profile: profile_data, follows_you: follows_you, damus: damus_state)
} }
} }
var followersCount: some View { var followersCount: some View {
HStack { HStack {
if followers.count == nil { if followers.count == nil {
@@ -384,26 +384,26 @@ struct ProfileView: View {
} }
} }
} }
var aboutSection: some View { var aboutSection: some View {
VStack(alignment: .leading, spacing: 8.0) { VStack(alignment: .leading, spacing: 8.0) {
let profile_data = damus_state.profiles.lookup(id: profile.pubkey) let profile_data = damus_state.profiles.lookup(id: profile.pubkey)
nameSection(profile_data: profile_data) nameSection(profile_data: profile_data)
if let about = profile_data?.about { if let about = profile_data?.about {
AboutView(state: damus_state, about: about) AboutView(state: damus_state, about: about)
} }
if let url = profile_data?.website_url { if let url = profile_data?.website_url {
WebsiteLink(url: url) WebsiteLink(url: url)
} }
HStack { HStack {
if let contact = profile.contacts { if let contact = profile.contacts {
let contacts = contact.referenced_pubkeys.map { $0.ref_id } let contacts = contact.referenced_pubkeys.map { $0.ref_id }
let following_model = FollowingModel(damus_state: damus_state, contacts: contacts) let following_model = FollowingModel(damus_state: damus_state, contacts: contacts)
NavigationLink(value: Route.Following(damusState: damus_state, following: following_model)) { NavigationLink(value: Route.Following(following: following_model)) {
HStack { HStack {
let noun_text = Text(verbatim: "\(followingCountString(profile.following))").font(.subheadline).foregroundColor(.gray) let noun_text = Text(verbatim: "\(followingCountString(profile.following))").font(.subheadline).foregroundColor(.gray)
Text("\(Text(verbatim: profile.following.formatted()).font(.subheadline.weight(.medium))) \(noun_text)", comment: "Sentence 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'.") Text("\(Text(verbatim: profile.following.formatted()).font(.subheadline.weight(.medium))) \(noun_text)", comment: "Sentence 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'.")
@@ -413,7 +413,7 @@ struct ProfileView: View {
} }
if followers.contacts != nil { if followers.contacts != nil {
NavigationLink(value: Route.Followers(damusState: damus_state, environmentObject: followers)) { NavigationLink(value: Route.Followers(environmentObject: followers)) {
followersCount followersCount
} }
.buttonStyle(PlainButtonStyle()) .buttonStyle(PlainButtonStyle())
@@ -425,18 +425,18 @@ struct ProfileView: View {
followers.subscribe() followers.subscribe()
} }
} }
if let relays = profile.relays { if let relays = profile.relays {
// Only open relay config view if the user is logged in with private key and they are looking at their own profile. // Only open relay config view if the user is logged in with private key and they are looking at their own profile.
let noun_text = Text(verbatim: relaysCountString(relays.keys.count)).font(.subheadline).foregroundColor(.gray) let noun_text = Text(verbatim: relaysCountString(relays.keys.count)).font(.subheadline).foregroundColor(.gray)
let relay_text = Text("\(Text(verbatim: relays.keys.count.formatted()).font(.subheadline.weight(.medium))) \(noun_text)", comment: "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'.") let relay_text = Text("\(Text(verbatim: relays.keys.count.formatted()).font(.subheadline.weight(.medium))) \(noun_text)", comment: "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'.")
if profile.pubkey == damus_state.pubkey && damus_state.is_privkey_user { if profile.pubkey == damus_state.pubkey && damus_state.is_privkey_user {
NavigationLink(value: Route.RelayConfig(damusState: damus_state)) { NavigationLink(value: Route.RelayConfig) {
relay_text relay_text
} }
.buttonStyle(PlainButtonStyle()) .buttonStyle(PlainButtonStyle())
} else { } else {
NavigationLink(value: Route.UserRelays(damusState: damus_state, relays: Array(relays.keys).sorted())) { NavigationLink(value: Route.UserRelays(relays: Array(relays.keys).sorted())) {
relay_text relay_text
} }
.buttonStyle(PlainButtonStyle()) .buttonStyle(PlainButtonStyle())
@@ -462,7 +462,7 @@ struct ProfileView: View {
} }
.padding(.horizontal) .padding(.horizontal)
} }
var body: some View { var body: some View {
ZStack { ZStack {
ScrollView(.vertical) { ScrollView(.vertical) {
@@ -540,7 +540,7 @@ struct ProfileView_Previews: PreviewProvider {
func test_damus_state() -> DamusState { func test_damus_state() -> DamusState {
let pubkey = "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681" let pubkey = "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"
let damus = DamusState.empty 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", damus_donation: nil) 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", damus_donation: nil)
let tsprof = TimestampedProfile(profile: prof, timestamp: 0, event: test_event) let tsprof = TimestampedProfile(profile: prof, timestamp: 0, event: test_event)
damus.profiles.add(id: pubkey, profile: tsprof) damus.profiles.add(id: pubkey, profile: tsprof)
@@ -549,15 +549,15 @@ func test_damus_state() -> DamusState {
struct KeyView: View { struct KeyView: View {
let pubkey: String let pubkey: String
@Environment(\.colorScheme) var colorScheme @Environment(\.colorScheme) var colorScheme
@State private var isCopied = false @State private var isCopied = false
func keyColor() -> Color { func keyColor() -> Color {
colorScheme == .light ? DamusColors.black : DamusColors.white colorScheme == .light ? DamusColors.black : DamusColors.white
} }
private func copyPubkey(_ pubkey: String) { private func copyPubkey(_ pubkey: String) {
UIPasteboard.general.string = pubkey UIPasteboard.general.string = pubkey
UIImpactFeedbackGenerator(style: .medium).impactOccurred() UIImpactFeedbackGenerator(style: .medium).impactOccurred()
@@ -570,10 +570,10 @@ struct KeyView: View {
} }
} }
} }
var body: some View { var body: some View {
let bech32 = bech32_pubkey(pubkey) ?? pubkey let bech32 = bech32_pubkey(pubkey) ?? pubkey
HStack { HStack {
Text(verbatim: "\(abbrev_pubkey(bech32, amount: 16))") Text(verbatim: "\(abbrev_pubkey(bech32, amount: 16))")
.font(.footnote) .font(.footnote)
@@ -581,7 +581,7 @@ struct KeyView: View {
.padding(5) .padding(5)
.padding([.leading, .trailing], 5) .padding([.leading, .trailing], 5)
.background(RoundedRectangle(cornerRadius: 11).foregroundColor(DamusColors.adaptableGrey)) .background(RoundedRectangle(cornerRadius: 11).foregroundColor(DamusColors.adaptableGrey))
if isCopied != true { if isCopied != true {
Button { Button {
copyPubkey(bech32) copyPubkey(bech32)

View File

@@ -72,7 +72,9 @@ struct RelayDetailView: View {
if let pubkey = nip11.pubkey { if let pubkey = nip11.pubkey {
Section(NSLocalizedString("Admin", comment: "Label to display relay contact user.")) { Section(NSLocalizedString("Admin", comment: "Label to display relay contact user.")) {
UserViewRow(damus_state: state, pubkey: pubkey) NavigationLink(value: Route.ProfileByKey(pubkey: pubkey), label: {
UserViewRow(damus_state: state, pubkey: pubkey)
})
} }
} }
if let relay_connection { if let relay_connection {

View File

@@ -30,8 +30,9 @@ struct RelayView: View {
if let meta = state.relay_metadata.lookup(relay_id: relay) { if let meta = state.relay_metadata.lookup(relay_id: relay) {
Text(relay) Text(relay)
.background( .background(
NavigationLink("", destination: RelayDetailView(state: state, relay: relay, nip11: meta)).opacity(0.0) NavigationLink(value: Route.RelayDetail(relay: relay, metadata: meta), label: {
.disabled(showActionButtons) EmptyView()
}).opacity(0.0).disabled(showActionButtons)
) )
Spacer() Spacer()

View File

@@ -14,7 +14,7 @@ struct SignalView: View {
var body: some View { var body: some View {
Group { Group {
if signal.signal != signal.max_signal { if signal.signal != signal.max_signal {
NavigationLink(destination: RelayConfigView(state: state)) { NavigationLink(value: Route.RelayConfig) {
Text("\(signal.signal)/\(signal.max_signal)", comment: "Fraction of how many of the user's relay servers that are operational.") Text("\(signal.signal)/\(signal.max_signal)", comment: "Fraction of how many of the user's relay servers that are operational.")
.font(.callout) .font(.callout)
.foregroundColor(.gray) .foregroundColor(.gray)

View File

@@ -16,9 +16,8 @@ struct RepostedEvent: View {
var body: some View { var body: some View {
VStack(alignment: .leading) { VStack(alignment: .leading) {
let prof = damus.profiles.lookup(id: event.pubkey) let prof = damus.profiles.lookup(id: event.pubkey)
let booster_profile = ProfileView(damus_state: damus, pubkey: event.pubkey)
NavigationLink(destination: booster_profile) { NavigationLink(value: Route.ProfileByKey(pubkey: event.pubkey)) {
Reposted(damus: damus, pubkey: event.pubkey, profile: prof) Reposted(damus: damus, pubkey: event.pubkey, profile: prof)
.padding(.horizontal) .padding(.horizontal)
} }

View File

@@ -100,14 +100,12 @@ struct SearchingEventView: View {
.progressViewStyle(.circular) .progressViewStyle(.circular)
} }
case .found(let ev): case .found(let ev):
NavigationLink(destination: ThreadView(state: state, thread: ThreadModel(event: ev, damus_state: state))) { NavigationLink(value: Route.Thread(thread: ThreadModel(event: ev, damus_state: state))) {
EventView(damus: state, event: ev) EventView(damus: state, event: ev)
} }
.buttonStyle(PlainButtonStyle()) .buttonStyle(PlainButtonStyle())
case .found_profile(let pk): case .found_profile(let pk):
NavigationLink(destination: ProfileView(damus_state: state, pubkey: pk)) { NavigationLink(value: Route.ProfileByKey(pubkey: pk)) {
FollowUserView(target: .pubkey(pk), damus_state: state) FollowUserView(target: .pubkey(pk), damus_state: state)
} }
.buttonStyle(PlainButtonStyle()) .buttonStyle(PlainButtonStyle())

View File

@@ -44,8 +44,7 @@ struct InnerSearchResults: View {
func HashtagSearch(_ ht: String) -> some View { func HashtagSearch(_ ht: String) -> some View {
let search_model = SearchModel(state: damus_state, search: .filter_hashtag([ht])) let search_model = SearchModel(state: damus_state, search: .filter_hashtag([ht]))
let dst = SearchView(appstate: damus_state, search: search_model) return NavigationLink(value: Route.Search(search: search_model)) {
return NavigationLink(destination: dst) {
Text("Search hashtag: #\(ht)", comment: "Navigation link to search hashtag.") Text("Search hashtag: #\(ht)", comment: "Navigation link to search hashtag.")
} }
} }

View File

@@ -11,23 +11,23 @@ struct SideMenuView: View {
let damus_state: DamusState let damus_state: DamusState
@Binding var isSidebarVisible: Bool @Binding var isSidebarVisible: Bool
@State var confirm_logout: Bool = false @State var confirm_logout: Bool = false
@State private var showQRCode = false @State private var showQRCode = false
@Environment(\.colorScheme) var colorScheme @Environment(\.colorScheme) var colorScheme
var sideBarWidth = min(UIScreen.main.bounds.size.width * 0.65, 400.0) var sideBarWidth = min(UIScreen.main.bounds.size.width * 0.65, 400.0)
let verticalSpacing: CGFloat = 20 let verticalSpacing: CGFloat = 20
let padding: CGFloat = 30 let padding: CGFloat = 30
func fillColor() -> Color { func fillColor() -> Color {
colorScheme == .light ? DamusColors.white : DamusColors.black colorScheme == .light ? DamusColors.white : DamusColors.black
} }
func textColor() -> Color { func textColor() -> Color {
colorScheme == .light ? DamusColors.black : DamusColors.white colorScheme == .light ? DamusColors.black : DamusColors.white
} }
var body: some View { var body: some View {
ZStack { ZStack {
GeometryReader { _ in GeometryReader { _ in
@@ -42,20 +42,20 @@ struct SideMenuView: View {
content content
} }
} }
func SidemenuItems(profile_model: ProfileModel, followers: FollowersModel) -> some View { func SidemenuItems(profile_model: ProfileModel, followers: FollowersModel) -> some View {
return VStack(spacing: verticalSpacing) { return VStack(spacing: verticalSpacing) {
NavigationLink(value: Route.Profile(damusSate: damus_state, profile: profile_model, followers: followers)) { NavigationLink(value: Route.Profile(profile: profile_model, followers: followers)) {
navLabel(title: NSLocalizedString("Profile", comment: "Sidebar menu label for Profile view."), img: "user") navLabel(title: NSLocalizedString("Profile", comment: "Sidebar menu label for Profile view."), img: "user")
} }
NavigationLink(destination: WalletView(damus_state: damus_state, model: damus_state.wallet)) { NavigationLink(destination: WalletView(damus_state: damus_state, model: damus_state.wallet)) {
navLabel(title: NSLocalizedString("Wallet", comment: "Sidebar menu label for Wallet view."), img: "wallet") navLabel(title: NSLocalizedString("Wallet", comment: "Sidebar menu label for Wallet view."), img: "wallet")
/* /*
HStack { HStack {
Image("wallet") Image("wallet")
.tint(DamusColors.adaptableBlack) .tint(DamusColors.adaptableBlack)
Text(NSLocalizedString("wallet", comment: "Sidebar menu label for Wallet view.")) Text(NSLocalizedString("wallet", comment: "Sidebar menu label for Wallet view."))
.font(.title2) .font(.title2)
.foregroundColor(textColor()) .foregroundColor(textColor())
@@ -63,36 +63,35 @@ struct SideMenuView: View {
.dynamicTypeSize(.xSmall) .dynamicTypeSize(.xSmall)
}*/ }*/
} }
NavigationLink(value: Route.MuteList(damusState: damus_state, users: get_mutelist_users(damus_state.contacts.mutelist))) { NavigationLink(value: Route.MuteList(users: get_mutelist_users(damus_state.contacts.mutelist))) {
navLabel(title: NSLocalizedString("Muted", comment: "Sidebar menu label for muted users view."), img: "mute") navLabel(title: NSLocalizedString("Muted", comment: "Sidebar menu label for muted users view."), img: "mute")
} }
NavigationLink(value: Route.RelayConfig(damusState: damus_state)) { NavigationLink(value: Route.RelayConfig) {
navLabel(title: NSLocalizedString("Relays", comment: "Sidebar menu label for Relays view."), img: "world-relays") navLabel(title: NSLocalizedString("Relays", comment: "Sidebar menu label for Relays view."), img: "world-relays")
} }
NavigationLink(value: Route.Bookmarks(damusState: damus_state)) { NavigationLink(value: Route.Bookmarks) {
navLabel(title: NSLocalizedString("Bookmarks", comment: "Sidebar menu label for Bookmarks view."), img: "bookmark") navLabel(title: NSLocalizedString("Bookmarks", comment: "Sidebar menu label for Bookmarks view."), img: "bookmark")
} }
NavigationLink(value: Route.Config(damusState: damus_state)) { NavigationLink(value: Route.Config) {
navLabel(title: NSLocalizedString("Settings", comment: "Sidebar menu label for accessing the app settings"), img: "settings") navLabel(title: NSLocalizedString("Settings", comment: "Sidebar menu label for accessing the app settings"), img: "settings")
} }
} }
} }
var MainSidemenu: some View { var MainSidemenu: some View {
VStack(alignment: .leading, spacing: 0) { VStack(alignment: .leading, spacing: 0) {
let profile = damus_state.profiles.lookup(id: damus_state.pubkey) let profile = damus_state.profiles.lookup(id: damus_state.pubkey)
let followers = FollowersModel(damus_state: damus_state, target: damus_state.pubkey) let followers = FollowersModel(damus_state: damus_state, target: damus_state.pubkey)
let profile_model = ProfileModel(pubkey: damus_state.pubkey, damus: damus_state) let profile_model = ProfileModel(pubkey: damus_state.pubkey, damus: damus_state)
NavigationLink(destination: ProfileView(damus_state: damus_state, profile: profile_model, followers: followers)) { NavigationLink(value: Route.Profile(profile: profile_model, followers: followers), label: {
HStack { HStack {
ProfilePicView(pubkey: damus_state.pubkey, size: 60, highlight: .none, profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation) ProfilePicView(pubkey: damus_state.pubkey, size: 60, highlight: .none, profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
VStack(alignment: .leading) { VStack(alignment: .leading) {
if let display_name = profile?.display_name { if let display_name = profile?.display_name {
Text(display_name) Text(display_name)
@@ -109,10 +108,10 @@ struct SideMenuView: View {
} }
} }
.padding(.bottom, verticalSpacing) .padding(.bottom, verticalSpacing)
} })
Divider() Divider()
ScrollView { ScrollView {
SidemenuItems(profile_model: profile_model, followers: followers) SidemenuItems(profile_model: profile_model, followers: followers)
.labelStyle(SideMenuLabelStyle()) .labelStyle(SideMenuLabelStyle())
@@ -120,7 +119,7 @@ struct SideMenuView: View {
} }
} }
} }
var content: some View { var content: some View {
HStack(alignment: .top) { HStack(alignment: .top) {
ZStack(alignment: .top) { ZStack(alignment: .top) {
@@ -186,20 +185,20 @@ struct SideMenuView: View {
Spacer() Spacer()
} }
} }
@ViewBuilder @ViewBuilder
func navLabel(title: String, img: String) -> some View { func navLabel(title: String, img: String) -> some View {
Image(img) Image(img)
.tint(DamusColors.adaptableBlack) .tint(DamusColors.adaptableBlack)
Text(title) Text(title)
.font(.title2) .font(.title2)
.foregroundColor(textColor()) .foregroundColor(textColor())
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
.dynamicTypeSize(.xSmall) .dynamicTypeSize(.xSmall)
} }
struct SideMenuLabelStyle: LabelStyle { struct SideMenuLabelStyle: LabelStyle {
func makeBody(configuration: Configuration) -> some View { func makeBody(configuration: Configuration) -> some View {
HStack(alignment: .center, spacing: 8) { HStack(alignment: .center, spacing: 8) {