// /* * Copyright (c) 2022 BWI GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import SwiftUI /// Helper class for making our SwiftUI view available to ObjectiveC @objcMembers class NotificationTimesViewController: NSObject { @available(iOS 14.0, *) class func makeViewController(session: MXSession) -> UIViewController { return UIHostingController(rootView: NotificationTimesView(session: session)) } } // MARK: - @available(iOS 14.0, *) struct NotificationTimesView: View { @Environment(\.presentationMode) var presentationMode @State var isOn: Bool @AppStorage("NotificationTimes_selectedDay") var selectedDay: Int = 0 @State var weekdays: [NotificationTimesWeekday] @State var hasChanges = false // MARK: Private @Environment(\.theme) private var theme var session: MXSession? init(session: MXSession?) { self.session = session if let session = session { RiotSharedSettings(session: session).fetchNotificationTimes() } self._isOn = State(initialValue: NotificationTimes.shared.isEnabled) self._weekdays = State(initialValue: [NotificationTimes.shared.monday.copy(), NotificationTimes.shared.tuesday.copy(), NotificationTimes.shared.wednesday.copy(), NotificationTimes.shared.thursday.copy(), NotificationTimes.shared.friday.copy(), NotificationTimes.shared.saturday.copy(), NotificationTimes.shared.sunday.copy()]) } var body: some View { VStack(spacing: 50) { NotificationTimesToggle(isOn: $isOn, valuesChanged: $hasChanges) .padding(.top, 40) if isOn { HStack { ForEach(weekdays) { weekday in WeekDayButton(weekday: weekday, selectedDay: $selectedDay) } } WeekDaysSettings(weekday: weekdays[selectedDay], valuesChanged: $hasChanges) } Spacer() } .padding() .navigationTitle(BWIL10n.bwiNotificationTimes) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button(action: onDoneButton) { Text(BWIL10n.bwiNotificationTimesDoneAction) .foregroundColor(hasChanges ? Color(ThemeService.shared().theme.tintColor) : Color.secondary) } .disabled(!hasChanges) } } .background(theme.colors.background) } private func onDoneButton() { hasChanges = false transferChanges(to: NotificationTimes.shared) storeToMatrixAccountData() NotificationTimes.storeToSharedUserDefaults() presentationMode.wrappedValue.dismiss() // dismiss the screen } private func transferChanges(to notificationTimes: NotificationTimes) { notificationTimes.isEnabled = isOn for i in 0...6 { notificationTimes.weekday(index: i).startTime = weekdays[i].startTime notificationTimes.weekday(index: i).endTime = weekdays[i].endTime notificationTimes.weekday(index: i).isEnabled = weekdays[i].isEnabled } } private func storeToMatrixAccountData() { if let session = session { _ = RiotSharedSettings(session: session).storeNotificationTimes { print("NotificationTimes successuflly stored to account data") } failure: { error in if let error = error { print("Error: Storing NotificationTimes into account data failed") print(error) } } } } } // MARK: - @available(iOS 14.0, *) fileprivate struct NotificationTimesToggle: View { @Binding var isOn: Bool @Binding var valuesChanged: Bool var body: some View { Toggle(isOn: $isOn) { VStack(alignment: .leading, spacing: 8) { Text(BWIL10n.bwiNotificationTimesToggleTitle) .font(.headline) .foregroundColor(.primary) Text(BWIL10n.bwiNotificationTimesToggleDescription) .font(.subheadline) .foregroundColor(.secondary) } } .toggleStyle(SwitchToggleStyle(tint: Color(ThemeService.shared().theme.tintColor))) .onChange(of: isOn) { _ in valuesChanged = true } } } // MARK: - @available(iOS 14.0, *) fileprivate struct WeekDayButton: View { @ObservedObject var weekday: NotificationTimesWeekday @Binding var selectedDay: Int var body: some View { Button(action: { selectedDay = weekday.id }) { ZStack { Group { if weekday.isEnabled { Circle() .foregroundColor(Color(ThemeService.shared().theme.tintColor)) } else { Circle() .strokeBorder(Color.secondary, lineWidth: 1) .background(Circle().fill(.clear)) } if weekday.isEnabled { Text(weekday.shortName) .font(.subheadline) .foregroundColor(Color(ThemeService.shared().theme.backgroundColor)) } else { Text(weekday.shortName) .font(.subheadline) .foregroundColor(Color(ThemeService.shared().theme.tintColor)) } } .frame(width: 38, height: 38) Circle() .strokeBorder( weekday.id == selectedDay ? .gray : .clear, lineWidth: 2) .frame(width: 45, height: 45) } } } } // MARK: - @available(iOS 14.0, *) fileprivate struct WeekDaysSettings: View { @ObservedObject var weekday: NotificationTimesWeekday @Binding var valuesChanged: Bool var body: some View { VStack(spacing: 0) { UserInfoText(weekdayName: weekday.name, notificationsEnabled: weekday.isEnabled) Spacer() .frame(height: 20) HStack(spacing: 40) { TimePicker(date: $weekday.startTime, title: BWIL10n.bwiNotificationTimesStartTime, enabled: weekday.isEnabled) TimePicker(date: $weekday.endTime, title: BWIL10n.bwiNotificationTimesEndTime, enabled: weekday.isEnabled) } Spacer() .frame(height: 50) Button(action: { weekday.isEnabled.toggle() valuesChanged = true }) { if weekday.isEnabled { Text(BWIL10n.bwiNotificationTimesButtonDeactivate(weekday.name)) .foregroundColor(Color(ThemeService.shared().theme.tintColor)) } else { Text(BWIL10n.bwiNotificationTimesButtonActivate(weekday.name)) .foregroundColor(Color(ThemeService.shared().theme.tintColor)) } } } .onChange(of: weekday.startTime) { newValue in if weekday.endTime < newValue { weekday.endTime = newValue } valuesChanged = true } .onChange(of: weekday.endTime) { newValue in if weekday.startTime > newValue { weekday.startTime = newValue } valuesChanged = true } } } @available(iOS 14.0, *) fileprivate struct UserInfoText: View { var weekdayName: String var notificationsEnabled: Bool var body: some View { if notificationsEnabled { TwoLineText(BWIL10n.bwiNotificationTimesStatusActivated(weekdayName), color: notificationsEnabled ? .primary : .secondary) } else { TwoLineText(BWIL10n.bwiNotificationTimesStatusDeactivated(weekdayName), color: notificationsEnabled ? .primary : .secondary) } } } @available(iOS 14.0, *) fileprivate struct TimePicker: View { @Binding var date: Date var title: String var enabled: Bool var body: some View { VStack { Text(title) .foregroundColor(enabled ? .primary : .secondary) ZStack { DatePicker( "", selection: $date, displayedComponents: [.hourAndMinute]) .labelsHidden() .opacity(enabled ? 1 : 0) Text("--:--") .foregroundColor(.secondary) .opacity(enabled ? 0 : 1) } } } } @available(iOS 14.0, *) fileprivate struct TwoLineText: View { var text: String var color: Color init(_ text: String, color: Color) { self.text = text self.color = color } var body: some View { ZStack { Text("X\nX") .frame(maxWidth: .infinity) .font(.body) .foregroundColor(.clear) Text(text) .lineLimit(2) .multilineTextAlignment(.center) .font(.body) .foregroundColor(color) } } } @available(iOS 14.0, *) struct NotificationTimesView_Previews: PreviewProvider { static var previews: some View { NavigationView { NotificationTimesView(session: nil) .environment(\.locale, Locale.init(identifier: "de")) } } }