Browse Source

Add a Sidebar

Changlog-Added: Sidebar
Closes: #273
translations_damus-localizations-en-us-xcloc-localized-contents-en-us-xliff--master_es_419
Ben Weeks 2 years ago
committed by William Casarin
parent
commit
40d11ad680
  1. 6
      damus.xcodeproj/project.pbxproj
  2. 92
      damus/ContentView.swift
  3. 12
      damus/Views/MainTabView.swift
  4. 2
      damus/Views/ProfileName.swift
  5. 176
      damus/Views/SideMenuView.swift
  6. 3
      damus/damusApp.swift

6
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 */,

92
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

12
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")
}
}
}

2
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)))

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

3
damus/damusApp.swift

@ -14,10 +14,7 @@ struct damusApp: App {
WindowGroup {
MainView()
}
}
}
struct MainView: View {

Loading…
Cancel
Save