commit 40d11ad680744a178921771fb1eb8a59769653d2
parent 4d8088d0d0e6e52e5c1cecf00f4417ee5e2b250f
Author: Ben Weeks <ben.weeks@outlook.com>
Date: Tue, 10 Jan 2023 10:07:35 -0800
Add a Sidebar
Changlog-Added: Sidebar
Closes: #273
Diffstat:
6 files changed, 238 insertions(+), 53 deletions(-)
diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj
@@ -138,6 +138,7 @@
4CEE2AF9280B2EAC00AB5EEF /* PowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2AF8280B2EAC00AB5EEF /* PowView.swift */; };
4CEE2B02280B39E800AB5EEF /* EventActionBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2B01280B39E800AB5EEF /* EventActionBar.swift */; };
4FE60CDD295E1C5E00105A1F /* Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE60CDC295E1C5E00105A1F /* Wallet.swift */; };
+ 647D9A8D2968520300A295DE /* SideMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 647D9A8C2968520300A295DE /* SideMenuView.swift */; };
64FBD06F296255C400D9D3B2 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64FBD06E296255C400D9D3B2 /* Theme.swift */; };
6C7DE41F2955169800E66263 /* Vault in Frameworks */ = {isa = PBXBuildFile; productRef = 6C7DE41E2955169800E66263 /* Vault */; };
BA693074295D649800ADDB87 /* UserSettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA693073295D649800ADDB87 /* UserSettingsStore.swift */; };
@@ -332,6 +333,7 @@
4CEE2AF8280B2EAC00AB5EEF /* PowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PowView.swift; sourceTree = "<group>"; };
4CEE2B01280B39E800AB5EEF /* EventActionBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventActionBar.swift; sourceTree = "<group>"; };
4FE60CDC295E1C5E00105A1F /* Wallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wallet.swift; sourceTree = "<group>"; };
+ 647D9A8C2968520300A295DE /* SideMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideMenuView.swift; sourceTree = "<group>"; };
64FBD06E296255C400D9D3B2 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
BA693073295D649800ADDB87 /* UserSettingsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettingsStore.swift; sourceTree = "<group>"; };
BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectWalletView.swift; sourceTree = "<group>"; };
@@ -488,7 +490,6 @@
4C3AC79E2833115300E1F516 /* FollowButtonView.swift */,
4C3AC79C2833036D00E1F516 /* FollowingView.swift */,
4C90BD17283A9EE5008EE7EF /* LoginView.swift */,
- 4C3AC7A42836987600E1F516 /* MainTabView.swift */,
4C363A8928236B57006E126D /* MentionView.swift */,
4C363A8D28236FE4006E126D /* NoteContentView.swift */,
4C75EFAC28049CFB0006080F /* PostButton.swift */,
@@ -498,6 +499,7 @@
4C285C892838B985008A31F1 /* ProfilePictureSelector.swift */,
4CEE2AF2280B25C500AB5EEF /* ProfilePicView.swift */,
4C8682862814DE470026224F /* ProfileView.swift */,
+ 4C3AC7A42836987600E1F516 /* MainTabView.swift */,
4C363A8B28236B92006E126D /* PubkeyView.swift */,
4CB55EF2295E5D59007FD187 /* RecommendedRelayView.swift */,
4C06670028FC7C5900038D2A /* RelayView.swift */,
@@ -513,6 +515,7 @@
4C0A3F96280F8E02000448DE /* ThreadView.swift */,
4CA2EF9F280E37AC0044ACD8 /* TimelineView.swift */,
4CB55EF4295E679D007FD187 /* UserRelaysView.swift */,
+ 647D9A8C2968520300A295DE /* SideMenuView.swift */,
);
path = Views;
sourceTree = "<group>";
@@ -824,6 +827,7 @@
4C363A9028247A1D006E126D /* NostrLink.swift in Sources */,
4C0A3F8C280F5FCA000448DE /* ChatroomView.swift in Sources */,
4C477C9E282C3A4800033AA3 /* TipCounter.swift in Sources */,
+ 647D9A8D2968520300A295DE /* SideMenuView.swift in Sources */,
4C0A3F91280F6528000448DE /* ChatView.swift in Sources */,
4C216F362870A9A700040376 /* InputDismissKeyboard.swift in Sources */,
4C216F382871EDE300040376 /* DirectMessageModel.swift in Sources */,
diff --git a/damus/ContentView.swift b/damus/ContentView.swift
@@ -80,6 +80,7 @@ struct ContentView: View {
@State var thread_open: Bool = false
@State var search_open: Bool = false
@State var filter_state : FilterState = .posts_and_replies
+ @State private var isSideBarOpened = false
@StateObject var home: HomeModel = HomeModel()
@StateObject var user_settings = UserSettingsStore()
@@ -220,46 +221,53 @@ struct ContentView: View {
VStack(alignment: .leading, spacing: 0) {
if let damus = self.damus_state {
NavigationView {
- MainContent(damus: damus)
- .toolbar {
- ToolbarItem(placement: .navigationBarLeading) {
- let profile_model = ProfileModel(pubkey: damus_state!.pubkey, damus: damus_state!)
- let followers_model = FollowersModel(damus_state: damus_state!, target: damus_state!.pubkey)
- let prof_dest = ProfileView(damus_state: damus_state!, profile: profile_model, followers: followers_model)
-
- NavigationLink(destination: prof_dest) {
- /// Verify that the user has a profile picture, if not display a generic SF Symbol
- /// (Resolves an in-app error where ``Robohash`` pictures are not generated so the button dissapears
- if let picture = damus_state?.profiles.lookup(id: pubkey)?.picture {
- ProfilePicView(pubkey: damus_state!.pubkey, size: 32, highlight: .none, profiles: damus_state!.profiles, picture: picture)
- } else {
- Image(systemName: "person.fill")
+ ZStack {
+ VStack {
+ MainContent(damus: damus)
+ .toolbar() {
+ ToolbarItem(placement: .navigationBarLeading) {
+ let profile_model = ProfileModel(pubkey: damus_state!.pubkey, damus: damus_state!)
+ let followers_model = FollowersModel(damus_state: damus_state!, target: damus_state!.pubkey)
+ Button {
+ isSideBarOpened.toggle()
+ } label: {
+ let profile_model = ProfileModel(pubkey: damus_state!.pubkey, damus: damus_state!)
+ let followers_model = FollowersModel(damus_state: damus_state!, target: damus_state!.pubkey)
+
+ if let picture = damus_state?.profiles.lookup(id: pubkey)?.picture {
+ ProfilePicView(pubkey: damus_state!.pubkey, size: 32, highlight: .none, profiles: damus_state!.profiles, picture: picture)
+ } else {
+ Image(systemName: "person.fill")
+ }
+ }
}
- }
- .buttonStyle(PlainButtonStyle())
- }
-
- ToolbarItem(placement: .navigationBarTrailing) {
- HStack(alignment: .center) {
- if home.signal.signal != home.signal.max_signal {
- Text("\(home.signal.signal)/\(home.signal.max_signal)", comment: "Fraction of how many of the user's relay servers that are operational.")
- .font(.callout)
- .foregroundColor(.gray)
- }
-
- NavigationLink(destination: ConfigView(state: damus_state!).environmentObject(user_settings)) {
- Label("", systemImage: "gear")
+
+ ToolbarItem(placement: .navigationBarTrailing) {
+ HStack(alignment: .center) {
+ if home.signal.signal != home.signal.max_signal {
+ Text("\(home.signal.signal)/\(home.signal.max_signal)", comment: "Fraction of how many of the user's relay servers that are operational.")
+ .font(.callout)
+ .foregroundColor(.gray)
+ }
+
+ }
}
- .buttonStyle(PlainButtonStyle())
}
- }
+
}
+
+ Color.clear
+ .overlay(
+ SideMenuView(damus_state: damus, isSidebarVisible: $isSideBarOpened)
+ )
+ }
+ .navigationBarHidden(isSideBarOpened ? true: false) // Would prefer a different way of doing this.
}
.navigationViewStyle(.stack)
+
+ TabBar(new_events: $home.new_events, selected: $selected_timeline, isSidebarVisible: $isSideBarOpened, action: switch_timeline)
+ .padding([.bottom], 8)
}
-
- TabBar(new_events: $home.new_events, selected: $selected_timeline, action: switch_timeline)
- .padding([.bottom], 8)
}
.onAppear() {
self.connect()
@@ -300,7 +308,6 @@ struct ContentView: View {
guard let privkey = self.privkey else {
return
}
-
let ev = notif.object as! NostrEvent
let boost = make_boost_event(pubkey: pubkey, privkey: privkey, boosted: ev)
self.damus_state?.pool.send(.event(boost))
@@ -333,10 +340,10 @@ struct ContentView: View {
let pk = target.pubkey
if let ev = unfollow_user(pool: damus.pool,
- our_contacts: damus.contacts.event,
- pubkey: damus.pubkey,
- privkey: privkey,
- unfollow: pk) {
+ our_contacts: damus.contacts.event,
+ pubkey: damus.pubkey,
+ privkey: privkey,
+ unfollow: pk) {
notify(.unfollowed, pk)
damus.contacts.event = ev
@@ -355,10 +362,10 @@ struct ContentView: View {
}
if let ev = follow_user(pool: damus.pool,
- our_contacts: damus.contacts.event,
- pubkey: damus.pubkey,
- privkey: privkey,
- follow: ReferencedId(ref_id: fnotify.pubkey, relay_id: nil, key: "p")) {
+ our_contacts: damus.contacts.event,
+ pubkey: damus.pubkey,
+ privkey: privkey,
+ follow: ReferencedId(ref_id: fnotify.pubkey, relay_id: nil, key: "p")) {
notify(.followed, fnotify.pubkey)
damus_state?.contacts.event = ev
@@ -448,7 +455,6 @@ struct ContentView_Previews: PreviewProvider {
}
}
-
func get_since_time(last_event: NostrEvent?) -> Int64? {
if let last_event = last_event {
return last_event.created_at - 60 * 10
diff --git a/damus/Views/MainTabView.swift b/damus/Views/MainTabView.swift
@@ -31,9 +31,9 @@ func timeline_bit(_ timeline: Timeline) -> Int {
struct TabButton: View {
let timeline: Timeline
let img: String
-
@Binding var selected: Timeline?
@Binding var new_events: NewEventsBits
+ @Binding var isSidebarVisible: Bool
let action: (Timeline) -> ()
@@ -56,6 +56,7 @@ struct TabButton: View {
Button(action: {
action(timeline)
new_events = NewEventsBits(prev: new_events, unsetting: timeline)
+ isSidebarVisible = false
}) {
Label("", systemImage: selected == timeline ? "\(img).fill" : img)
.contentShape(Rectangle())
@@ -69,6 +70,7 @@ struct TabButton: View {
struct TabBar: View {
@Binding var new_events: NewEventsBits
@Binding var selected: Timeline?
+ @Binding var isSidebarVisible: Bool
let action: (Timeline) -> ()
@@ -76,10 +78,10 @@ struct TabBar: View {
VStack {
Divider()
HStack {
- 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")
+ TabButton(timeline: .home, img: "house", selected: $selected, new_events: $new_events, isSidebarVisible: $isSidebarVisible, action: action).keyboardShortcut("1")
+ TabButton(timeline: .dms, img: "bubble.left.and.bubble.right", selected: $selected, new_events: $new_events, isSidebarVisible: $isSidebarVisible, action: action).keyboardShortcut("2")
+ TabButton(timeline: .search, img: "magnifyingglass.circle", selected: $selected, new_events: $new_events, isSidebarVisible: $isSidebarVisible, action: action).keyboardShortcut("3")
+ TabButton(timeline: .notifications, img: "bell", selected: $selected, new_events: $new_events, isSidebarVisible: $isSidebarVisible, action: action).keyboardShortcut("4")
}
}
}
diff --git a/damus/Views/ProfileName.swift b/damus/Views/ProfileName.swift
@@ -144,7 +144,7 @@ struct EventProfileName: View {
.padding([.trailing], 2)
Text("@" + String(display_name ?? Profile.displayName(profile: profile, pubkey: pubkey)))
- .foregroundColor(.gray)
+ .foregroundColor(Color("DamusMediumGrey"))
.font(eventviewsize_to_font(size))
} else {
Text(String(display_name ?? Profile.displayName(profile: profile, pubkey: pubkey)))
diff --git a/damus/Views/SideMenuView.swift b/damus/Views/SideMenuView.swift
@@ -0,0 +1,176 @@
+//
+// SideMenuView.swift
+// damus
+//
+// Created by Ben Weeks on 1/6/23.
+// Ref: https://blog.logrocket.com/create-custom-collapsible-sidebar-swiftui/
+
+import SwiftUI
+
+struct SideMenuView: View {
+ let damus_state: DamusState
+ @Binding var isSidebarVisible: Bool
+
+ @State var confirm_logout: Bool = false
+ @StateObject var user_settings = UserSettingsStore()
+
+ @Environment(\.colorScheme) var colorScheme
+
+ var sideBarWidth = UIScreen.main.bounds.size.width * 0.65
+
+ func fillColor() -> Color {
+ colorScheme == .light ? Color("DamusWhite") : Color("DamusBlack")
+ }
+
+ func textColor() -> Color {
+ colorScheme == .light ? Color("DamusBlack") : Color("DamusWhite")
+ }
+
+ var body: some View {
+ ZStack {
+ GeometryReader { _ in
+ EmptyView()
+ }
+ .background(Color("DamusDarkGrey").opacity(0.6))
+ .opacity(isSidebarVisible ? 1 : 0)
+ .animation(.easeInOut.delay(0.2), value: isSidebarVisible)
+ .onTapGesture {
+ isSidebarVisible.toggle()
+ }
+ content
+ }
+ .edgesIgnoringSafeArea(.all)
+
+ }
+
+ var content: some View {
+ HStack(alignment: .top) {
+ ZStack(alignment: .top) {
+ fillColor()
+
+ VStack(alignment: .leading, spacing: 20) {
+ let profile = damus_state.profiles.lookup(id: damus_state.pubkey)
+
+ if let picture = damus_state.profiles.lookup(id: damus_state.pubkey)?.picture {
+ ProfilePicView(pubkey: damus_state.pubkey, size: 60, highlight: .none, profiles: damus_state.profiles, picture: picture)
+ } else {
+ Image(systemName: "person.fill")
+ }
+ VStack(alignment: .leading) {
+ if let display_name = profile?.display_name {
+ Text(display_name)
+ .foregroundColor(textColor())
+ .font(.title)
+ }
+ if let name = profile?.name {
+ Text("@" + name)
+ .foregroundColor(Color("DamusMediumGrey"))
+ .font(.body)
+ }
+ }
+
+ Divider()
+ .padding(.trailing,40)
+
+ /*
+ HStack(alignment: .bottom) {
+ Text("69,420")
+ .foregroundColor(.accentColor)
+ .font(.largeTitle)
+ Text("SATS")
+ .font(.caption)
+ .padding(.bottom,6)
+ }
+
+ Divider()
+ .padding(.trailing,40)
+ */
+
+ // THERE IS A LIMIT OF 10 NAVIGATIONLINKS!!! (Consider some in other views)
+
+ let followers = FollowersModel(damus_state: damus_state, target: damus_state.pubkey)
+ let profile_model = ProfileModel(pubkey: damus_state.pubkey, damus: damus_state)
+
+ NavigationLink(destination: ProfileView(damus_state: damus_state, profile: profile_model, followers: followers)) {
+ Label("Profile", systemImage: "person")
+ .font(.title2)
+ .foregroundColor(textColor())
+ }
+ .simultaneousGesture(TapGesture().onEnded {
+ isSidebarVisible = false
+ })
+
+ /*
+ NavigationLink(destination: EmptyView()) {
+ Label("Relays", systemImage: "xserve")
+ .font(.title2)
+ .foregroundColor(textColor())
+ }
+ .simultaneousGesture(TapGesture().onEnded {
+ isSidebarVisible.toggle()
+ })
+ */
+
+ /*
+ NavigationLink(destination: EmptyView()) {
+ Label("Wallet", systemImage: "bolt")
+ .font(.title2)
+ .foregroundColor(textColor())
+ }
+ .simultaneousGesture(TapGesture().onEnded {
+ isSidebarVisible.toggle()
+ })
+ */
+
+ NavigationLink(destination: ConfigView(state: damus_state).environmentObject(user_settings)) {
+ Label("App settings", systemImage: "gear")
+ .font(.title2)
+ .foregroundColor(textColor())
+ }
+ .simultaneousGesture(TapGesture().onEnded {
+ isSidebarVisible = false
+ })
+
+ Spacer()
+
+ Button(action: {
+ //ConfigView(state: damus_state)
+ confirm_logout = true
+ }, label: {
+ Label("Sign out", systemImage: "pip.exit")
+ .font(.title3)
+ .foregroundColor(textColor())
+ })
+ }
+ .padding(.top, 60)
+ .padding(.bottom, 40)
+ .padding(.leading, 40)
+ }
+ .frame(width: sideBarWidth)
+ .offset(x: isSidebarVisible ? 0 : -sideBarWidth)
+ .animation(.default, value: isSidebarVisible)
+ .onTapGesture {
+ isSidebarVisible.toggle()
+ }
+ .alert("Logout", isPresented: $confirm_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")
+ }
+
+ Spacer()
+ }
+ }
+}
+
+struct Previews_SideMenuView_Previews: PreviewProvider {
+ static var previews: some View {
+ let ds = test_damus_state()
+ SideMenuView(damus_state: ds, isSidebarVisible: .constant(true))
+ }
+}
diff --git a/damus/damusApp.swift b/damus/damusApp.swift
@@ -14,10 +14,7 @@ struct damusApp: App {
WindowGroup {
MainView()
}
-
}
-
-
}
struct MainView: View {