3a0acfaba1
This commit implements a new layer called NostrNetworkManager, responsible for managing interactions with the Nostr network, and providing a higher level API that is easier and more secure to use for the layer above it. It also integrates it with the rest of the app, by moving RelayPool and PostBox into NostrNetworkManager, along with all their usages. Changelog-Added: Added NIP-65 relay list support Changelog-Changed: Improved robustness of relay list handling Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
219 lines
8.2 KiB
Swift
219 lines
8.2 KiB
Swift
//
|
|
// UserStatusSheet.swift
|
|
// damus
|
|
//
|
|
// Created by William Casarin on 2023-08-23.
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
enum StatusDuration: CustomStringConvertible, CaseIterable {
|
|
case never
|
|
case thirty_mins
|
|
case hour
|
|
case four_hours
|
|
case day
|
|
case week
|
|
|
|
var timeInterval: TimeInterval? {
|
|
switch self {
|
|
case .never:
|
|
return nil
|
|
case .thirty_mins:
|
|
return 60 * 30
|
|
case .hour:
|
|
return 60 * 60
|
|
case .four_hours:
|
|
return 60 * 60 * 4
|
|
case .day:
|
|
return 60 * 60 * 24
|
|
case .week:
|
|
return 60 * 60 * 24 * 7
|
|
}
|
|
}
|
|
|
|
var expiration: Date? {
|
|
guard let timeInterval else {
|
|
return nil
|
|
}
|
|
|
|
return Date.now.addingTimeInterval(timeInterval)
|
|
}
|
|
|
|
var description: String {
|
|
guard let timeInterval else {
|
|
return NSLocalizedString("Never", comment: "Profile status duration setting of never expiring.")
|
|
}
|
|
|
|
let formatter = DateComponentsFormatter()
|
|
formatter.unitsStyle = .full
|
|
formatter.allowedUnits = [.minute, .hour, .day, .weekOfMonth]
|
|
return formatter.string(from: timeInterval) ?? "\(timeInterval) seconds"
|
|
}
|
|
}
|
|
|
|
enum Fields{
|
|
case status
|
|
case link
|
|
}
|
|
|
|
struct UserStatusSheet: View {
|
|
let damus_state: DamusState
|
|
let postbox: PostBox
|
|
let keypair: Keypair
|
|
|
|
@State var duration: StatusDuration = .never
|
|
@State var show_link: Bool = false
|
|
|
|
@ObservedObject var status: UserStatusModel
|
|
@Environment(\.colorScheme) var colorScheme
|
|
@Environment(\.dismiss) var dismiss
|
|
|
|
var status_binding: Binding<String> {
|
|
Binding(get: {
|
|
status.general?.content ?? ""
|
|
}, set: { v in
|
|
if let general = status.general {
|
|
status.general = UserStatus(type: .general, expires_at: duration.expiration, content: v, created_at: UInt32(Date.now.timeIntervalSince1970), url: general.url)
|
|
} else {
|
|
status.general = UserStatus(type: .general, expires_at: duration.expiration, content: v, created_at: UInt32(Date.now.timeIntervalSince1970), url: nil)
|
|
}
|
|
})
|
|
}
|
|
|
|
var url_binding: Binding<String> {
|
|
Binding(get: {
|
|
status.general?.url?.absoluteString ?? ""
|
|
}, set: { v in
|
|
if let general = status.general {
|
|
status.general = UserStatus(type: .general, expires_at: duration.expiration, content: general.content, created_at: UInt32(Date.now.timeIntervalSince1970), url: URL(string: v))
|
|
} else {
|
|
status.general = UserStatus(type: .general, expires_at: duration.expiration, content: "", created_at: UInt32(Date.now.timeIntervalSince1970), url: URL(string: v))
|
|
}
|
|
})
|
|
}
|
|
|
|
var body: some View {
|
|
// This is needed to prevent the view from being moved when the keyboard is shown
|
|
GeometryReader { geometry in
|
|
VStack {
|
|
HStack {
|
|
Button(action: {
|
|
dismiss()
|
|
}, label: {
|
|
Text("Cancel", comment: "Cancel button text for dismissing profile status settings view.")
|
|
.padding(10)
|
|
})
|
|
.buttonStyle(NeutralButtonStyle())
|
|
|
|
Spacer()
|
|
|
|
Button(action: {
|
|
guard let status = self.status.general,
|
|
let kp = keypair.to_full(),
|
|
let ev = make_user_status_note(status: status, keypair: kp, expiry: duration.expiration)
|
|
else {
|
|
return
|
|
}
|
|
|
|
postbox.send(ev)
|
|
|
|
dismiss()
|
|
}, label: {
|
|
Text("Share", comment: "Save button text for saving profile status settings.")
|
|
})
|
|
.buttonStyle(GradientButtonStyle(padding: 10))
|
|
}
|
|
.padding(5)
|
|
|
|
Divider()
|
|
|
|
ZStack(alignment: .top) {
|
|
ProfilePicView(pubkey: keypair.pubkey, size: 120.0, highlight: .custom(DamusColors.white, 3.0), profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation)
|
|
.padding(.top, 30)
|
|
|
|
VStack(spacing: 0) {
|
|
HStack {
|
|
TextField(NSLocalizedString("Staying humble...", comment: "Placeholder as an example of what the user could set as their profile status."), text: status_binding, axis: .vertical)
|
|
.autocorrectionDisabled(true)
|
|
.textInputAutocapitalization(.never)
|
|
.lineLimit(3)
|
|
.frame(width: 175)
|
|
|
|
}
|
|
.padding(10)
|
|
.background(colorScheme == .light ? .white : DamusColors.neutral3)
|
|
.cornerRadius(15)
|
|
.shadow(color: colorScheme == .light ? DamusColors.neutral3 : .clear, radius: 15)
|
|
|
|
Circle()
|
|
.fill(colorScheme == .light ? .white : DamusColors.neutral3)
|
|
.frame(width: 12, height: 12)
|
|
.padding(.trailing, 140)
|
|
|
|
Circle()
|
|
.fill(colorScheme == .light ? .white : DamusColors.neutral3)
|
|
.frame(width: 7, height: 7)
|
|
.padding(.trailing, 120)
|
|
|
|
}
|
|
.padding(.leading, 60)
|
|
}
|
|
|
|
VStack {
|
|
HStack {
|
|
Image("link")
|
|
.foregroundColor(DamusColors.neutral3)
|
|
|
|
TextField(text: url_binding, label: {
|
|
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.")
|
|
})
|
|
.autocorrectionDisabled(true)
|
|
}
|
|
.padding(10)
|
|
.cornerRadius(12)
|
|
.overlay(
|
|
RoundedRectangle(cornerRadius: 12)
|
|
.stroke(DamusColors.neutral3, lineWidth: 1)
|
|
)
|
|
}
|
|
.padding()
|
|
|
|
Toggle(isOn: $status.playing_enabled, label: {
|
|
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.")
|
|
})
|
|
.tint(DamusColors.purple)
|
|
.padding(.horizontal)
|
|
|
|
HStack {
|
|
Text("Clear status", comment: "Label to prompt user to select an expiration time for the profile status to clear.")
|
|
|
|
Spacer()
|
|
|
|
Picker(NSLocalizedString("Duration", comment: "Label for profile status expiration duration picker."), selection: $duration) {
|
|
ForEach(StatusDuration.allCases, id: \.self) { d in
|
|
Text(d.description)
|
|
.tag(d)
|
|
}
|
|
}
|
|
}
|
|
.padding()
|
|
|
|
Spacer()
|
|
|
|
}
|
|
.padding(.top)
|
|
.background(DamusColors.adaptableWhite.edgesIgnoringSafeArea(.all))
|
|
}
|
|
.dismissKeyboardOnTap()
|
|
.ignoresSafeArea(.keyboard, edges: .bottom)
|
|
}
|
|
}
|
|
|
|
|
|
struct UserStatusSheet_Previews: PreviewProvider {
|
|
static var previews: some View {
|
|
UserStatusSheet(damus_state: test_damus_state, postbox: test_damus_state.nostrNetwork.postbox, keypair: test_keypair, status: .init())
|
|
}
|
|
}
|