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 }