UserStatusMessageSwiftUIView.swift 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. //
  2. // SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
  3. // SPDX-License-Identifier: GPL-3.0-or-later
  4. //
  5. import SwiftUI
  6. import NextcloudKit
  7. struct UserStatusMessageSwiftUIView: View {
  8. @Environment(\.dismiss) var dismiss
  9. @Binding var changed: Bool
  10. @State var showClearAtAlert: Bool = false
  11. @State private var selectedPredefinedMessageId: String?
  12. @State private var predefinedStatuses: [NKUserStatus] = []
  13. @State private var selectedIcon: String = ""
  14. @State private var selectedMessage: String = ""
  15. @State private var selectedClearAt: Double = 0
  16. @State private var selectedClearAtString: String = ""
  17. @State private var userHasStatusSet: Bool = false
  18. @State private var isLoading: Bool = true
  19. @FocusState private var textFieldIsFocused: Bool
  20. @State private var showErrorAlert = false
  21. @State private var errorAlertTitle = ""
  22. @State private var errorAlertMessage = ""
  23. let clearAtOptions = [
  24. NSLocalizedString("Don't clear", comment: ""),
  25. NSLocalizedString("30 minutes", comment: ""),
  26. NSLocalizedString("1 hour", comment: ""),
  27. NSLocalizedString("4 hours", comment: ""),
  28. NSLocalizedString("Today", comment: ""),
  29. NSLocalizedString("This week", comment: "")
  30. ]
  31. var body: some View {
  32. VStack(alignment: .center) {
  33. if isLoading {
  34. ProgressView()
  35. .tint(.secondary)
  36. } else {
  37. List {
  38. Section(header: Text(NSLocalizedString("What is your status?", comment: ""))) {
  39. HStack(spacing: 10) {
  40. SingleEmojiTextFieldWrapper(placeholder: "😀", text: $selectedIcon)
  41. .frame(maxWidth: 23)
  42. .opacity(selectedIcon.isEmpty ? 0.5 : 1.0)
  43. .onChange(of: selectedIcon) { _ in
  44. selectedPredefinedMessageId = nil
  45. }
  46. .tint(.primary)
  47. .focused($textFieldIsFocused)
  48. Divider()
  49. TextField(NSLocalizedString("What is your status?", comment: ""), text: $selectedMessage)
  50. .onChange(of: selectedMessage) { _ in
  51. selectedPredefinedMessageId = nil
  52. }
  53. .tint(.primary)
  54. .focused($textFieldIsFocused)
  55. }
  56. }
  57. Section {
  58. ForEach(predefinedStatuses, id: \.id) { status in
  59. Button(action: {
  60. selectedPredefinedMessageId = status.id
  61. selectedIcon = status.icon ?? ""
  62. selectedMessage = status.message ?? ""
  63. selectedClearAt = status.clearAt?.timeIntervalSince1970 ?? 0
  64. selectedClearAtString = getPredefinedClearStatusText(clearAt: status.clearAt, clearAtTime: status.clearAtTime, clearAtType: status.clearAtType)
  65. setClearAt(clearAt: selectedClearAtString)
  66. }) {
  67. HStack(spacing: 20) {
  68. Text(status.icon ?? " ")
  69. VStack(alignment: .leading) {
  70. Text(status.message ?? "")
  71. .foregroundColor(.primary)
  72. Text(getPredefinedClearStatusText(clearAt: status.clearAt, clearAtTime: status.clearAtTime, clearAtType: status.clearAtType))
  73. .font(.subheadline)
  74. .foregroundColor(.secondary)
  75. .lineLimit(1)
  76. }
  77. Spacer()
  78. }
  79. }
  80. }
  81. }
  82. Section {
  83. Button(action: {
  84. showClearAtAlert.toggle()
  85. }) {
  86. VStack(alignment: .leading) {
  87. Text(NSLocalizedString("Clear status message after", comment: ""))
  88. .foregroundColor(.primary)
  89. Text(selectedClearAtString)
  90. .font(.subheadline)
  91. .foregroundColor(.secondary)
  92. .lineLimit(1)
  93. }
  94. }
  95. }
  96. }
  97. if !UIDevice.current.orientation.isLandscape {
  98. VStack(spacing: 10) {
  99. NCButtonSwiftUI(title: NSLocalizedString("Clear status message",
  100. comment: ""),
  101. action: clearActiveUserStatus,
  102. style: .tertiary, height: 40,
  103. disabled: Binding.constant(!userHasStatusSet))
  104. NCButtonSwiftUI(title: NSLocalizedString("Set status message", comment: ""),
  105. action: setActiveUserStatus,
  106. style: .primary, height: 40,
  107. disabled: Binding.constant(selectedMessage.isEmpty && selectedIcon.isEmpty))
  108. .padding(.bottom, 16)
  109. }
  110. } else {
  111. HStack(spacing: 10) {
  112. Spacer()
  113. NCButtonSwiftUI(title: NSLocalizedString("Clear status message",
  114. comment: ""),
  115. action: clearActiveUserStatus,
  116. style: .tertiary, height: 40,
  117. disabled: Binding.constant(!userHasStatusSet))
  118. .padding(.bottom, 16)
  119. NCButtonSwiftUI(title: NSLocalizedString("Set status message", comment: ""),
  120. action: setActiveUserStatus,
  121. style: .primary, height: 40,
  122. disabled: Binding.constant(selectedMessage.isEmpty && selectedIcon.isEmpty))
  123. .padding(.bottom, 16)
  124. Spacer()
  125. }
  126. }
  127. }
  128. }
  129. .frame(maxWidth: .infinity, maxHeight: .infinity)
  130. .background(Color(uiColor: .systemGroupedBackground))
  131. .navigationBarTitle(Text(NSLocalizedString("Status message", comment: "")), displayMode: .inline)
  132. .navigationBarHidden(false)
  133. .onAppear {
  134. getStatus()
  135. }
  136. .confirmationDialog("Clear status message after", isPresented: $showClearAtAlert, titleVisibility: .visible) {
  137. Button("Don't clear") {
  138. selectedClearAtString = "Don't clear"
  139. showClearAtAlert = false
  140. setClearAt(clearAt: NSLocalizedString("Don't clear", comment: ""))
  141. }
  142. Button("30 minutes") {
  143. selectedClearAtString = "30 minutes"
  144. showClearAtAlert = false
  145. setClearAt(clearAt: NSLocalizedString("30 minutes", comment: ""))
  146. }
  147. Button("1 hour") {
  148. selectedClearAtString = "1 hour"
  149. showClearAtAlert = false
  150. setClearAt(clearAt: NSLocalizedString("1 hour", comment: ""))
  151. }
  152. Button("4 hours") {
  153. selectedClearAtString = "4 hours"
  154. showClearAtAlert = false
  155. setClearAt(clearAt: NSLocalizedString("4 hours", comment: ""))
  156. }
  157. Button("Today") {
  158. selectedClearAtString = "Today"
  159. showClearAtAlert = false
  160. setClearAt(clearAt: NSLocalizedString("Today", comment: ""))
  161. }
  162. Button("This week") {
  163. selectedClearAtString = "This week"
  164. showClearAtAlert = false
  165. setClearAt(clearAt: NSLocalizedString("This week", comment: ""))
  166. }
  167. }
  168. .alert(isPresented: $showErrorAlert) {
  169. Alert(title: Text(errorAlertTitle), message: Text(errorAlertMessage), dismissButton: .cancel())
  170. }
  171. }
  172. func getStatus() {
  173. isLoading = true
  174. NCAPIController.sharedInstance().setupNCCommunication(for: NCDatabaseManager.sharedInstance().activeAccount())
  175. NextcloudKit.shared.getUserStatus { _, clearAt, icon, message, messageId, _, _, _, _, _, error in
  176. if error.errorCode == 0 {
  177. userHasStatusSet = !(icon?.isEmpty ?? true) || !(message?.isEmpty ?? true)
  178. selectedIcon = icon ?? ""
  179. selectedMessage = message ?? ""
  180. selectedPredefinedMessageId = messageId
  181. selectedClearAt = clearAt?.timeIntervalSince1970 ?? 0
  182. selectedClearAtString = getPredefinedClearStatusText(clearAt: clearAt, clearAtTime: nil, clearAtType: nil)
  183. }
  184. }
  185. NextcloudKit.shared.getUserStatusPredefinedStatuses { _, userStatuses, _, error in
  186. if error.errorCode == 0 {
  187. predefinedStatuses = userStatuses ?? []
  188. withAnimation {
  189. isLoading = false
  190. }
  191. }
  192. }
  193. }
  194. func setActiveUserStatus() {
  195. if let selectedPredefinedMessageId {
  196. NextcloudKit.shared.setCustomMessagePredefined(messageId: selectedPredefinedMessageId, clearAt: selectedClearAt) { _, error in
  197. if error.errorCode == 0 {
  198. dismiss()
  199. changed.toggle()
  200. } else {
  201. triggerErrorAlert(title: NSLocalizedString("Could not set status message", comment: ""),
  202. message: NSLocalizedString("An error occurred while setting status message", comment: ""))
  203. }
  204. }
  205. } else {
  206. let statusIcon = selectedIcon.isEmpty ? nil : selectedIcon
  207. NextcloudKit.shared.setCustomMessageUserDefined(statusIcon: statusIcon, message: selectedMessage, clearAt: selectedClearAt) { _, error in
  208. if error.errorCode == 0 {
  209. dismiss()
  210. changed.toggle()
  211. } else {
  212. triggerErrorAlert(title: NSLocalizedString("Could not set status message", comment: ""), message: NSLocalizedString("An error occurred while setting status message", comment: ""))
  213. }
  214. }
  215. }
  216. }
  217. func clearActiveUserStatus() {
  218. NextcloudKit.shared.clearMessage { _, error in
  219. if error.errorCode == 0 {
  220. dismiss()
  221. changed.toggle()
  222. } else {
  223. triggerErrorAlert(title: NSLocalizedString("Could not clear status message", comment: ""), message: NSLocalizedString("An error occurred while clearing status message", comment: ""))
  224. }
  225. }
  226. }
  227. func triggerErrorAlert(title: String, message: String) {
  228. errorAlertTitle = title
  229. errorAlertMessage = message
  230. showErrorAlert.toggle()
  231. }
  232. func getClearAt(_ clearAtString: String) -> Double {
  233. let now = Date()
  234. let calendar = Calendar.current
  235. let gregorian = Calendar(identifier: .gregorian)
  236. let midnight = calendar.startOfDay(for: now)
  237. guard let tomorrow = calendar.date(byAdding: .day, value: 1, to: midnight) else { return 0 }
  238. guard let startweek = gregorian.date(from: gregorian.dateComponents([.yearForWeekOfYear, .weekOfYear], from: now)) else { return 0 }
  239. guard let endweek = gregorian.date(byAdding: .day, value: 6, to: startweek) else { return 0 }
  240. switch clearAtString {
  241. case NSLocalizedString("Don't clear", comment: ""):
  242. return 0
  243. case NSLocalizedString("30 minutes", comment: ""):
  244. let date = now.addingTimeInterval(1800)
  245. return date.timeIntervalSince1970
  246. case NSLocalizedString("1 hour", comment: ""), NSLocalizedString("an hour", comment: ""):
  247. let date = now.addingTimeInterval(3600)
  248. return date.timeIntervalSince1970
  249. case NSLocalizedString("4 hours", comment: ""):
  250. let date = now.addingTimeInterval(14400)
  251. return date.timeIntervalSince1970
  252. case NSLocalizedString("Today", comment: ""):
  253. return tomorrow.timeIntervalSince1970
  254. case NSLocalizedString("This week", comment: ""):
  255. return endweek.timeIntervalSince1970
  256. default:
  257. return 0
  258. }
  259. }
  260. func setClearAt(clearAt: String) {
  261. selectedClearAt = getClearAt(clearAt)
  262. selectedClearAtString = clearAt
  263. }
  264. func getPredefinedClearStatusText(clearAt: NSDate?, clearAtTime: String?, clearAtType: String?) -> String {
  265. if clearAt != nil {
  266. let from = Date()
  267. let to = clearAt! as Date
  268. let day = Calendar.current.dateComponents([.day], from: from, to: to).day ?? 0
  269. let hour = Calendar.current.dateComponents([.hour], from: from, to: to).hour ?? 0
  270. let minute = Calendar.current.dateComponents([.minute], from: from, to: to).minute ?? 0
  271. if day > 0 {
  272. if day == 1 { return NSLocalizedString("Today", comment: "") }
  273. return "\(day) " + NSLocalizedString("days", comment: "")
  274. }
  275. if hour > 0 {
  276. if hour == 1 { return NSLocalizedString("an hour", comment: "") }
  277. if hour == 4 { return NSLocalizedString("4 hours", comment: "") }
  278. return "\(hour) " + NSLocalizedString("hours", comment: "")
  279. }
  280. if minute > 0 {
  281. if minute >= 25 && minute <= 30 { return NSLocalizedString("30 minutes", comment: "") }
  282. if minute > 30 { return NSLocalizedString("an hour", comment: "") }
  283. return "\(minute) " + NSLocalizedString("minutes", comment: "")
  284. }
  285. }
  286. // Period
  287. if clearAtTime != nil && clearAtType == "period" {
  288. switch clearAtTime {
  289. case "14400":
  290. return NSLocalizedString("4 hours", comment: "")
  291. case "3600":
  292. return NSLocalizedString("an hour", comment: "")
  293. case "1800":
  294. return NSLocalizedString("30 minutes", comment: "")
  295. default:
  296. return clearAtTime!
  297. }
  298. }
  299. // End of
  300. if clearAtTime != nil && clearAtType == "end-of" {
  301. switch clearAtTime {
  302. case "day":
  303. return NSLocalizedString("Today", comment: "")
  304. case "week":
  305. return NSLocalizedString("This week", comment: "")
  306. default:
  307. return clearAtTime!
  308. }
  309. }
  310. return NSLocalizedString("Don't clear", comment: "")
  311. }
  312. }
  313. struct UserStatusMessageSwiftUIView_Previews: PreviewProvider {
  314. static var previews: some View {
  315. UserStatusMessageSwiftUIView(changed: Binding.constant(false))
  316. }
  317. }