damus

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

UserStatusSheet.swift (8400B)


      1 //
      2 //  UserStatusSheet.swift
      3 //  damus
      4 //
      5 //  Created by William Casarin on 2023-08-23.
      6 //
      7 
      8 import SwiftUI
      9 
     10 enum StatusDuration: CustomStringConvertible, CaseIterable {
     11     case never
     12     case thirty_mins
     13     case hour
     14     case four_hours
     15     case day
     16     case week
     17 
     18     var timeInterval: TimeInterval? {
     19         switch self {
     20         case .never:
     21             return nil
     22         case .thirty_mins:
     23             return 60 * 30
     24         case .hour:
     25             return 60 * 60
     26         case .four_hours:
     27             return 60 * 60 * 4
     28         case .day:
     29             return 60 * 60 * 24
     30         case .week:
     31             return 60 * 60 * 24 * 7
     32         }
     33     }
     34 
     35     var expiration: Date? {
     36         guard let timeInterval else {
     37             return nil
     38         }
     39 
     40         return Date.now.addingTimeInterval(timeInterval)
     41     }
     42 
     43     var description: String {
     44         guard let timeInterval else {
     45             return NSLocalizedString("Never", comment: "Profile status duration setting of never expiring.")
     46         }
     47 
     48         let formatter = DateComponentsFormatter()
     49         formatter.unitsStyle = .full
     50         formatter.allowedUnits = [.minute, .hour, .day, .weekOfMonth]
     51         return formatter.string(from: timeInterval) ?? "\(timeInterval) seconds"
     52     }
     53 }
     54 
     55 enum Fields{
     56     case status
     57     case link
     58 }
     59 
     60 struct UserStatusSheet: View {
     61     let damus_state: DamusState
     62     let postbox: PostBox
     63     let keypair: Keypair
     64 
     65     @State var duration: StatusDuration = .never
     66     @State var show_link: Bool = false
     67     
     68     @ObservedObject var status: UserStatusModel
     69     @Environment(\.colorScheme) var colorScheme
     70     @Environment(\.dismiss) var dismiss
     71 
     72     var status_binding: Binding<String> {
     73         Binding(get: {
     74             status.general?.content ?? ""
     75         }, set: { v in
     76             if let general = status.general {
     77                 status.general = UserStatus(type: .general, expires_at: duration.expiration, content: v, created_at: UInt32(Date.now.timeIntervalSince1970), url: general.url)
     78             } else {
     79                 status.general = UserStatus(type: .general, expires_at: duration.expiration, content: v, created_at: UInt32(Date.now.timeIntervalSince1970), url: nil)
     80             }
     81         })
     82     }
     83 
     84     var url_binding: Binding<String> {
     85         Binding(get: {
     86             status.general?.url?.absoluteString ?? ""
     87         }, set: { v in
     88             if let general = status.general {
     89                 status.general = UserStatus(type: .general, expires_at: duration.expiration, content: general.content, created_at: UInt32(Date.now.timeIntervalSince1970), url: URL(string: v))
     90             } else {
     91                 status.general = UserStatus(type: .general, expires_at: duration.expiration, content: "", created_at: UInt32(Date.now.timeIntervalSince1970), url: URL(string: v))
     92             }
     93         })
     94     }
     95 
     96     var body: some View {
     97         // This is needed to prevent the view from being moved when the keyboard is shown
     98         GeometryReader { geometry in
     99             VStack {
    100                 HStack {
    101                     Button(action: {
    102                         dismiss()
    103                     }, label: {
    104                         Text("Cancel", comment: "Cancel button text for dismissing profile status settings view.")
    105                             .padding(10)
    106                     })
    107                     .buttonStyle(NeutralButtonStyle())
    108                     
    109                     Spacer()
    110                     
    111                     Button(action: {
    112                         guard let status = self.status.general,
    113                               let kp = keypair.to_full(),
    114                               let ev = make_user_status_note(status: status, keypair: kp, expiry: duration.expiration)
    115                         else {
    116                             return
    117                         }
    118                         
    119                         postbox.send(ev)
    120                         
    121                         dismiss()
    122                     }, label: {
    123                         Text("Share", comment: "Save button text for saving profile status settings.")
    124                     })
    125                     .buttonStyle(GradientButtonStyle(padding: 10))
    126                 }
    127                 .padding(5)
    128                 
    129                 Divider()
    130                 
    131                 ZStack(alignment: .top) {
    132                     ProfilePicView(pubkey: keypair.pubkey, size: 120.0, highlight: .custom(DamusColors.white, 3.0), profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
    133                         .padding(.top, 30)
    134                     
    135                     VStack(spacing: 0) {
    136                         HStack {
    137                             TextField(NSLocalizedString("Staying humble...", comment: "Placeholder as an example of what the user could set as their profile status."), text: status_binding, axis: .vertical)
    138                                 .autocorrectionDisabled(true)
    139                                 .textInputAutocapitalization(.never)
    140                                 .lineLimit(3)
    141                                 .frame(width: 175)
    142                             
    143                         }
    144                         .padding(10)
    145                         .background(colorScheme == .light ? .white : DamusColors.neutral3)
    146                         .cornerRadius(15)
    147                         .shadow(color: colorScheme == .light ? DamusColors.neutral3 : .clear, radius: 15)
    148                         
    149                         Circle()
    150                             .fill(colorScheme == .light ? .white : DamusColors.neutral3)
    151                             .frame(width: 12, height: 12)
    152                             .padding(.trailing, 140)
    153                         
    154                         Circle()
    155                             .fill(colorScheme == .light ? .white : DamusColors.neutral3)
    156                             .frame(width: 7, height: 7)
    157                             .padding(.trailing, 120)
    158                         
    159                     }
    160                     .padding(.leading, 60)
    161                 }
    162                 
    163                 VStack {
    164                     HStack {
    165                         Image("link")
    166                             .foregroundColor(DamusColors.neutral3)
    167                         
    168                         TextField(text: url_binding, label: {
    169                             Text("Add an external link", comment: "Placeholder as an example of what the user could set so that the link is opened when the status is tapped.")
    170                         })
    171                         .autocorrectionDisabled(true)
    172                     }
    173                     .padding(10)
    174                     .cornerRadius(12)
    175                     .overlay(
    176                         RoundedRectangle(cornerRadius: 12)
    177                             .stroke(DamusColors.neutral3, lineWidth: 1)
    178                     )
    179                 }
    180                 .padding()
    181                 
    182                 Toggle(isOn: $status.playing_enabled, label: {
    183                     Text("Broadcast music playing on Apple Music", comment: "Toggle to enable or disable broadcasting what music is being played on Apple Music in their profile status.")
    184                 })
    185                 .tint(DamusColors.purple)
    186                 .padding(.horizontal)
    187                 
    188                 HStack {
    189                     Text("Clear status", comment: "Label to prompt user to select an expiration time for the profile status to clear.")
    190                     
    191                     Spacer()
    192                     
    193                     Picker(NSLocalizedString("Duration", comment: "Label for profile status expiration duration picker."), selection: $duration) {
    194                         ForEach(StatusDuration.allCases, id: \.self) { d in
    195                             Text(d.description)
    196                                 .tag(d)
    197                         }
    198                     }
    199                 }
    200                 .padding()
    201                 
    202                 Spacer()
    203                 
    204             }
    205             .padding(.top)
    206             .background(DamusColors.adaptableWhite.edgesIgnoringSafeArea(.all))
    207         }
    208         .dismissKeyboardOnTap()
    209         .ignoresSafeArea(.keyboard, edges: .bottom)
    210     }
    211 }
    212 
    213 
    214 struct UserStatusSheet_Previews: PreviewProvider {
    215     static var previews: some View {
    216         UserStatusSheet(damus_state: test_damus_state, postbox: test_damus_state.postbox, keypair: test_keypair, status: .init())
    217     }
    218 }