Finish extraction

- Moves SwiftUI code out of Riot and into RiotSwiftUI which has no dependency on Matrix SDK.
- Git wasn't smart enough to see the file moves. Most feature function has remain unchanged. 1 change I did make was remove NotificationSettingsViewModel's dependence on MxPushRule, so that the view model could be moved into RiotSwiftUI.
- Add LocaleProvider to abstract VectorL10n's use of Matrix SDK language so it can be used in RiotSwiftUI.
- Split Theme into UKit/SwiftUI version to remove RiotSwiftUI's dependence on ThemeService and ThemeV1.
- Migrated from ThemeObserver to ThemePublisher. We push updates to ThemePublisher so that we can remove ThemeService as dependency.
- Add .DS_Store to .gitignore
This commit is contained in:
David Langley
2021-09-01 12:34:38 +01:00
parent cb0403ed8d
commit ada377dcf2
93 changed files with 921 additions and 259 deletions
@@ -0,0 +1,27 @@
//
// Copyright 2021 New Vector Ltd
//
// 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 Foundation
typealias UpdateRoomNotificationStateCompletion = () -> Void
typealias RoomNotificationStateCallback = (RoomNotificationState) -> Void
protocol RoomNotificationSettingsServiceType {
func observeNotificationState(listener: @escaping RoomNotificationStateCallback)
func update(state: RoomNotificationState, completion: @escaping UpdateRoomNotificationStateCompletion)
var notificationState: RoomNotificationState { get }
}
@@ -0,0 +1,36 @@
//
// Copyright 2021 New Vector Ltd
//
// 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 Foundation
import Combine
@available(iOS 14.0, *)
class RoomNotificationSettingsSwiftUIViewModel: RoomNotificationSettingsViewModel, ObservableObject {
@Published var viewState: RoomNotificationSettingsViewState
lazy var cancellables = Set<AnyCancellable>()
override init(roomNotificationService: RoomNotificationSettingsServiceType, initialState: RoomNotificationSettingsViewState) {
self.viewState = initialState
super.init(roomNotificationService: roomNotificationService, initialState: initialState)
}
override func update(viewState: RoomNotificationSettingsViewState) {
super.update(viewState: viewState)
self.viewState = viewState
}
}
@@ -0,0 +1,26 @@
// File created from ScreenTemplate
// $ createScreen.sh Room/NotificationSettings RoomNotificationSettings
/*
Copyright 2021 New Vector Ltd
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 Foundation
/// RoomNotificationSettingsViewController view actions exposed to view model
enum RoomNotificationSettingsViewAction {
case load
case selectNotificationState(RoomNotificationState)
case save
case cancel
}
@@ -0,0 +1,108 @@
// File created from ScreenTemplate
// $ createScreen.sh Room/NotificationSettings RoomNotificationSettings
/*
Copyright 2021 New Vector Ltd
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 Foundation
import Combine
class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModelType {
// MARK: - Properties
// MARK: Private
private let roomNotificationService: RoomNotificationSettingsServiceType
var state: RoomNotificationSettingsViewState {
willSet {
update(viewState: newValue)
}
}
// MARK: Public
weak var viewDelegate: RoomNotificationSettingsViewModelViewDelegate?
weak var coordinatorDelegate: RoomNotificationSettingsViewModelCoordinatorDelegate?
// MARK: - Setup
init(
roomNotificationService: RoomNotificationSettingsServiceType,
initialState: RoomNotificationSettingsViewState
) {
self.roomNotificationService = roomNotificationService
self.state = initialState
self.roomNotificationService.observeNotificationState { [weak self] state in
guard let self = self else { return }
self.state.notificationState = Self.mapNotificationStateOnRead(encrypted: self.state.roomEncrypted, state: state)
}
}
convenience init(
roomNotificationService: RoomNotificationSettingsServiceType,
avatarData: AvatarType?,
displayName: String?,
roomEncrypted: Bool
) {
let notificationState = Self.mapNotificationStateOnRead(encrypted: roomEncrypted, state: roomNotificationService.notificationState)
let initialState = RoomNotificationSettingsViewState(
roomEncrypted: roomEncrypted,
saving: false,
notificationState: notificationState,
avatarData: avatarData,
displayName: displayName
)
self.init(roomNotificationService: roomNotificationService, initialState: initialState)
}
// MARK: - Public
func process(viewAction: RoomNotificationSettingsViewAction) {
switch viewAction {
case .load:
update(viewState: self.state)
case .selectNotificationState(let state):
self.state.notificationState = state
case .save:
self.state.saving = true
roomNotificationService.update(state: state.notificationState) { [weak self] in
guard let self = self else { return }
self.state.saving = false
self.coordinatorDelegate?.roomNotificationSettingsViewModelDidComplete(self)
}
case .cancel:
coordinatorDelegate?.roomNotificationSettingsViewModelDidCancel(self)
}
}
// MARK: - Private
private static func mapNotificationStateOnRead(encrypted: Bool, state: RoomNotificationState) -> RoomNotificationState {
if encrypted, case .mentionsAndKeywordsOnly = state {
// Notifications not supported on encrypted rooms, map mentionsOnly to mute on read
return .mute
} else {
return state
}
}
func update(viewState: RoomNotificationSettingsViewState) {
self.viewDelegate?.roomNotificationSettingsViewModel(self, didUpdateViewState: viewState)
}
}
@@ -0,0 +1,37 @@
// File created from ScreenTemplate
// $ createScreen.sh Room/NotificationSettings RoomNotificationSettings
/*
Copyright 2021 New Vector Ltd
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 Foundation
protocol RoomNotificationSettingsViewModelViewDelegate: AnyObject {
func roomNotificationSettingsViewModel(_ viewModel: RoomNotificationSettingsViewModelType, didUpdateViewState viewState: RoomNotificationSettingsViewStateType)
}
protocol RoomNotificationSettingsViewModelCoordinatorDelegate: AnyObject {
func roomNotificationSettingsViewModelDidComplete(_ viewModel: RoomNotificationSettingsViewModelType)
func roomNotificationSettingsViewModelDidCancel(_ viewModel: RoomNotificationSettingsViewModelType)
}
/// Protocol describing the view model used by `RoomNotificationSettingsViewController`
protocol RoomNotificationSettingsViewModelType {
var viewDelegate: RoomNotificationSettingsViewModelViewDelegate? { get set }
var coordinatorDelegate: RoomNotificationSettingsViewModelCoordinatorDelegate? { get set }
func process(viewAction: RoomNotificationSettingsViewAction)
}
@@ -0,0 +1,53 @@
// File created from ScreenTemplate
// $ createScreen.sh Room/NotificationSettings RoomNotificationSettings
/*
Copyright 2021 New Vector Ltd
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 Foundation
/// RoomNotificationSettingsViewController view state
struct RoomNotificationSettingsViewState: RoomNotificationSettingsViewStateType {
let roomEncrypted: Bool
var saving: Bool
var notificationState: RoomNotificationState
var avatarData: AvatarType?
var displayName: String?
}
extension RoomNotificationSettingsViewState {
var notificationOptions: [RoomNotificationState] {
if roomEncrypted {
return [.all, .mute]
} else {
return RoomNotificationState.allCases
}
}
}
protocol RoomNotificationSettingsViewStateType {
var saving: Bool { get }
var roomEncrypted: Bool { get }
var notificationOptions: [RoomNotificationState] { get }
var notificationState: RoomNotificationState { get }
var avatarData: AvatarType? { get }
var displayName: String? { get }
}
extension RoomNotificationSettingsViewState {
var roomEncryptedString: String {
roomEncrypted ? VectorL10n.roomNotifsSettingsEncryptedRoomNotice : ""
}
}