damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

SideMenuView.swift (9877B)


      1 //
      2 //  SideMenuView.swift
      3 //  damus
      4 //
      5 //  Created by Ben Weeks on 1/6/23.
      6 //  Ref: https://blog.logrocket.com/create-custom-collapsible-sidebar-swiftui/
      7 
      8 import SwiftUI
      9 
     10 @MainActor
     11 struct SideMenuView: View {
     12     let damus_state: DamusState
     13     @Binding var isSidebarVisible: Bool
     14     @State var confirm_logout: Bool = false
     15     @State private var showQRCode = false
     16     
     17     @Environment(\.colorScheme) var colorScheme
     18 
     19     var sideBarWidth = min(UIScreen.main.bounds.size.width * 0.65, 400.0)
     20     let verticalSpacing: CGFloat = 20
     21     let padding: CGFloat = 30
     22 
     23     func fillColor() -> Color {
     24         colorScheme == .light ? DamusColors.white : DamusColors.black
     25     }
     26 
     27     func textColor() -> Color {
     28         colorScheme == .light ? DamusColors.black : DamusColors.white
     29     }
     30 
     31     var body: some View {
     32         ZStack {
     33             GeometryReader { _ in
     34                 EmptyView()
     35             }
     36             .background(DamusColors.darkGrey.opacity(0.6))
     37             .opacity(isSidebarVisible ? 1 : 0)
     38             .animation(.default, value: isSidebarVisible)
     39             .onTapGesture {
     40                 isSidebarVisible.toggle()
     41             }
     42 
     43             content
     44         }
     45     }
     46 
     47     func SidemenuItems(profile_model: ProfileModel, followers: FollowersModel) -> some View {
     48         return VStack(spacing: verticalSpacing) {
     49             NavigationLink(value: Route.Profile(profile: profile_model, followers: followers)) {
     50                 navLabel(title: NSLocalizedString("Profile", comment: "Sidebar menu label for Profile view."), img: "user")
     51             }
     52 
     53             NavigationLink(value: Route.Wallet(wallet: damus_state.wallet)) {
     54                 navLabel(title: NSLocalizedString("Wallet", comment: "Sidebar menu label for Wallet view."), img: "wallet")
     55             }
     56 
     57             if damus_state.purple.enable_purple {
     58                 NavigationLink(destination: DamusPurpleView(damus_state: damus_state)) {
     59                     HStack(spacing: 13) {
     60                         Image("nostr-hashtag")
     61                         Text("Purple")
     62                             .foregroundColor(DamusColors.purple)
     63                             .font(.title2.weight(.bold))
     64                     }
     65                     .frame(maxWidth: .infinity, alignment: .leading)
     66                 }
     67             }
     68 
     69             NavigationLink(value: Route.MuteList) {
     70                 navLabel(title: NSLocalizedString("Muted", comment: "Sidebar menu label for muted users view."), img: "mute")
     71             }
     72 
     73             NavigationLink(value: Route.RelayConfig) {
     74                 navLabel(title: NSLocalizedString("Relays", comment: "Sidebar menu label for Relays view."), img: "world-relays")
     75             }
     76 
     77             NavigationLink(value: Route.Bookmarks) {
     78                 navLabel(title: NSLocalizedString("Bookmarks", comment: "Sidebar menu label for Bookmarks view."), img: "bookmark")
     79             }
     80 
     81             Link(destination: URL(string: "https://store.damus.io/?ref=damus_ios_app")!) {
     82                 navLabel(title: NSLocalizedString("Merch", comment: "Sidebar menu label for merch store link."), img: "basket")
     83             }
     84 
     85             NavigationLink(value: Route.Config) {
     86                 navLabel(title: NSLocalizedString("Settings", comment: "Sidebar menu label for accessing the app settings"), img: "settings")
     87             }
     88         }
     89     }
     90 
     91     var TopProfile: some View {
     92         var name: String? = nil
     93         var display_name: String? = nil
     94 
     95         do {
     96             let profile_txn = damus_state.ndb.lookup_profile(damus_state.pubkey, txn_name: "top_profile")
     97             let profile = profile_txn?.unsafeUnownedValue?.profile
     98             name = profile?.name
     99             display_name = profile?.display_name
    100         }
    101 
    102         return VStack(alignment: .leading, spacing: verticalSpacing) {
    103             HStack {
    104                 ProfilePicView(pubkey: damus_state.pubkey, size: 60, highlight: .none, profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
    105 
    106                 VStack(alignment: .leading) {
    107 
    108                     if let display_name {
    109                         Text(display_name)
    110                             .foregroundColor(textColor())
    111                             .font(.title)
    112                             .lineLimit(1)
    113                     }
    114                     if let name {
    115                         Text("@" + name)
    116                             .foregroundColor(DamusColors.mediumGrey)
    117                             .font(.body)
    118                             .lineLimit(1)
    119                     }
    120                 }
    121             }
    122 
    123             navLabel(title: NSLocalizedString("Set Status", comment: "Sidebar menu label to set user status"), img: "add-reaction")
    124                 .font(.title2)
    125                 .foregroundColor(textColor())
    126                 .frame(maxWidth: .infinity, alignment: .leading)
    127                 .dynamicTypeSize(.xSmall)
    128                 .onTapGesture {
    129                     present_sheet(.user_status)
    130                 }
    131 
    132             UserStatusView(status: damus_state.profiles.profile_data(damus_state.pubkey).status, show_general: true, show_music: true)
    133                 .dynamicTypeSize(.xSmall)
    134         }
    135     }
    136 
    137     var MainSidemenu: some View {
    138         VStack(alignment: .leading, spacing: 0) {
    139             let followers = FollowersModel(damus_state: damus_state, target: damus_state.pubkey)
    140             let profile_model = ProfileModel(pubkey: damus_state.pubkey, damus: damus_state)
    141 
    142             NavigationLink(value: Route.Profile(profile: profile_model, followers: followers), label: {
    143 
    144                 TopProfile
    145                     .padding(.bottom, verticalSpacing)
    146             })
    147 
    148             Divider()
    149 
    150             ScrollView {
    151                 SidemenuItems(profile_model: profile_model, followers: followers)
    152                     .labelStyle(SideMenuLabelStyle())
    153                     .padding([.top, .bottom], verticalSpacing)
    154             }
    155         }
    156     }
    157 
    158     var content: some View {
    159         HStack(alignment: .top) {
    160             ZStack(alignment: .top) {
    161                 fillColor()
    162                     .ignoresSafeArea()
    163 
    164                 VStack(alignment: .leading, spacing: 0) {
    165                     MainSidemenu
    166                     .simultaneousGesture(TapGesture().onEnded {
    167                         isSidebarVisible = false
    168                     })
    169 
    170                     Divider()
    171 
    172                     HStack() {
    173                         Button(action: {
    174                             //ConfigView(state: damus_state)
    175                             if damus_state.keypair.privkey == nil {
    176                                 logout(damus_state)
    177                             } else {
    178                                 confirm_logout = true
    179                             }
    180                         }, label: {
    181                             Label(NSLocalizedString("Sign out", comment: "Sidebar menu label to sign out of the account."), image: "logout")
    182                                 .font(.title3)
    183                                 .foregroundColor(textColor())
    184                                 .frame(maxWidth: .infinity, alignment: .leading)
    185                                 .dynamicTypeSize(.xSmall)
    186                         })
    187 
    188                         Spacer()
    189 
    190                         Button(action: {
    191                             showQRCode.toggle()
    192                         }, label: {
    193                             Image("qr-code")
    194                                 .font(.title)
    195                                 .foregroundColor(textColor())
    196                                 .dynamicTypeSize(.xSmall)
    197                         }).fullScreenCover(isPresented: $showQRCode) {
    198                             QRCodeView(damus_state: damus_state, pubkey: damus_state.pubkey)
    199                         }
    200                     }
    201                     .padding(.top, verticalSpacing)
    202                 }
    203                 .padding(.top, -(padding / 2.0))
    204                 .padding([.leading, .trailing, .bottom], padding)
    205             }
    206             .frame(width: sideBarWidth)
    207             .offset(x: isSidebarVisible ? 0 : -(sideBarWidth + padding))
    208             .animation(.default, value: isSidebarVisible)
    209             .alert("Logout", isPresented: $confirm_logout) {
    210                 Button(NSLocalizedString("Cancel", comment: "Cancel out of logging out the user."), role: .cancel) {
    211                     confirm_logout = false
    212                 }
    213                 Button(NSLocalizedString("Logout", comment: "Button for logging out the user."), role: .destructive) {
    214                     logout(damus_state)
    215                 }
    216             } message: {
    217                 Text("Make sure your nsec account key is saved before you logout or you will lose access to this account", comment: "Reminder message in alert to get customer to verify that their private security account key is saved saved before logging out.")
    218             }
    219 
    220             Spacer()
    221         }
    222     }
    223 
    224     func navLabel(title: String, img: String) -> some View {
    225         HStack {
    226             Image(img)
    227                 .tint(DamusColors.adaptableBlack)
    228             
    229             Text(title)
    230                 .font(.title2)
    231                 .foregroundColor(textColor())
    232                 .frame(maxWidth: .infinity, alignment: .leading)
    233                 .dynamicTypeSize(.xSmall)
    234         }
    235     }
    236 
    237     struct SideMenuLabelStyle: LabelStyle {
    238         func makeBody(configuration: Configuration) -> some View {
    239             HStack(alignment: .center, spacing: 8) {
    240                 configuration.icon
    241                     .frame(width: 24, height: 24)
    242                     .aspectRatio(contentMode: .fit)
    243                 configuration.title
    244             }
    245         }
    246     }
    247 }
    248 
    249 struct Previews_SideMenuView_Previews: PreviewProvider {
    250     static var previews: some View {
    251         let ds = test_damus_state
    252         SideMenuView(damus_state: ds, isSidebarVisible: .constant(true))
    253     }
    254 }