mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-25 19:10:49 +02:00
Configured and applied SwiftFormat
This commit is contained in:
committed by
Stefan Ceriu
parent
ff2e6ddfa7
commit
43c28d23b7
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
@@ -14,15 +14,14 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
typealias AllChatsOnboardingViewModelType = StateStoreViewModel<AllChatsOnboardingViewState,
|
||||
Never,
|
||||
AllChatsOnboardingViewAction>
|
||||
Never,
|
||||
AllChatsOnboardingViewAction>
|
||||
|
||||
class AllChatsOnboardingViewModel: AllChatsOnboardingViewModelType, AllChatsOnboardingViewModelProtocol {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -34,7 +33,7 @@ class AllChatsOnboardingViewModel: AllChatsOnboardingViewModelType, AllChatsOnbo
|
||||
// MARK: - Setup
|
||||
|
||||
static func makeAllChatsOnboardingViewModel() -> AllChatsOnboardingViewModelProtocol {
|
||||
return AllChatsOnboardingViewModel()
|
||||
AllChatsOnboardingViewModel()
|
||||
}
|
||||
|
||||
private init() {
|
||||
@@ -42,7 +41,7 @@ class AllChatsOnboardingViewModel: AllChatsOnboardingViewModelType, AllChatsOnbo
|
||||
}
|
||||
|
||||
private static func defaultState() -> AllChatsOnboardingViewState {
|
||||
return AllChatsOnboardingViewState(pages: [
|
||||
AllChatsOnboardingViewState(pages: [
|
||||
AllChatsOnboardingPageData(image: Asset.Images.allChatsOnboarding1.image,
|
||||
title: VectorL10n.allChatsOnboardingPageTitle1,
|
||||
message: VectorL10n.allChatsOnboardingPageMessage1),
|
||||
|
||||
+1
-2
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import Foundation
|
||||
|
||||
protocol AllChatsOnboardingViewModelProtocol {
|
||||
|
||||
var completion: ((AllChatsOnboardingViewModelResult) -> Void)? { get set }
|
||||
static func makeAllChatsOnboardingViewModel() -> AllChatsOnboardingViewModelProtocol
|
||||
var context: AllChatsOnboardingViewModelType.Context { get }
|
||||
|
||||
+4
-7
@@ -14,12 +14,11 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import CommonKit
|
||||
import SwiftUI
|
||||
|
||||
/// All Chats onboarding screen
|
||||
final class AllChatsOnboardingCoordinator: NSObject, Coordinator, Presentable {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -42,8 +41,8 @@ final class AllChatsOnboardingCoordinator: NSObject, Coordinator, Presentable {
|
||||
let viewModel = AllChatsOnboardingViewModel.makeAllChatsOnboardingViewModel()
|
||||
let view = AllChatsOnboarding(viewModel: viewModel.context)
|
||||
self.viewModel = viewModel
|
||||
self.hostingController = VectorHostingController(rootView: view)
|
||||
self.indicatorPresenter = UserIndicatorTypePresenter(presentingViewController: hostingController)
|
||||
hostingController = VectorHostingController(rootView: view)
|
||||
indicatorPresenter = UserIndicatorTypePresenter(presentingViewController: hostingController)
|
||||
|
||||
super.init()
|
||||
|
||||
@@ -65,7 +64,7 @@ final class AllChatsOnboardingCoordinator: NSObject, Coordinator, Presentable {
|
||||
}
|
||||
|
||||
func toPresentable() -> UIViewController {
|
||||
return self.hostingController
|
||||
hostingController
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
@@ -87,9 +86,7 @@ final class AllChatsOnboardingCoordinator: NSObject, Coordinator, Presentable {
|
||||
// MARK: - UIAdaptivePresentationControllerDelegate
|
||||
|
||||
extension AllChatsOnboardingCoordinator: UIAdaptivePresentationControllerDelegate {
|
||||
|
||||
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
|
||||
completion?()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-3
@@ -26,7 +26,6 @@ import Foundation
|
||||
/// Each bridge should be removed once the underlying Coordinator has been integrated by another Coordinator.
|
||||
@objcMembers
|
||||
final class AllChatsOnboardingCoordinatorBridgePresenter: NSObject {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -53,7 +52,7 @@ final class AllChatsOnboardingCoordinatorBridgePresenter: NSObject {
|
||||
}
|
||||
|
||||
func dismiss(animated: Bool, completion: (() -> Void)?) {
|
||||
guard let coordinator = self.coordinator else {
|
||||
guard let coordinator = coordinator else {
|
||||
return
|
||||
}
|
||||
coordinator.toPresentable().dismiss(animated: animated) {
|
||||
@@ -62,4 +61,3 @@ final class AllChatsOnboardingCoordinatorBridgePresenter: NSObject {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct AllChatsOnboarding: View {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -36,12 +35,12 @@ struct AllChatsOnboarding: View {
|
||||
.foregroundColor(theme.colors.primaryContent)
|
||||
.padding()
|
||||
TabView(selection: $selectedTab) {
|
||||
ForEach(viewModel.viewState.pages.indices) { index in
|
||||
ForEach(viewModel.viewState.pages.indices, id: \.self) { index in
|
||||
let page = viewModel.viewState.pages[index]
|
||||
AllChatsOnboardingPage(image: page.image,
|
||||
title: page.title,
|
||||
message: page.message)
|
||||
.tag(index)
|
||||
.tag(index)
|
||||
}
|
||||
}
|
||||
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .automatic))
|
||||
@@ -61,7 +60,7 @@ struct AllChatsOnboarding: View {
|
||||
// MARK: - Private
|
||||
|
||||
private func onCallToAction() {
|
||||
if (selectedTab == viewModel.viewState.pages.count - 1) {
|
||||
if selectedTab == viewModel.viewState.pages.count - 1 {
|
||||
viewModel.send(viewAction: .cancel)
|
||||
} else {
|
||||
withAnimation {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2022 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct AllChatsOnboardingPage: View {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
let image: UIImage
|
||||
@@ -55,7 +54,7 @@ struct AllChatsOnboardingPage_Previews: PreviewProvider {
|
||||
preview.theme(.dark).preferredColorScheme(.dark)
|
||||
}
|
||||
|
||||
static private var preview: some View {
|
||||
private static var preview: some View {
|
||||
AllChatsOnboardingPage(image: Asset.Images.allChatsOnboarding1.image,
|
||||
title: VectorL10n.allChatsOnboardingPageTitle1,
|
||||
message: VectorL10n.allChatsOnboardingPageMessage1)
|
||||
|
||||
+7
-9
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -25,7 +25,6 @@ import Foundation
|
||||
/// Each bridge should be removed once the underlying Coordinator has been integrated by another Coordinator.
|
||||
@objcMembers
|
||||
final class RoomNotificationSettingsCoordinatorBridgePresenter: NSObject {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -61,11 +60,11 @@ final class RoomNotificationSettingsCoordinatorBridgePresenter: NSObject {
|
||||
viewController.present(navigationController, animated: animated, completion: nil)
|
||||
roomNotificationSettingsCoordinator.start()
|
||||
|
||||
self.coordinator = roomNotificationSettingsCoordinator
|
||||
coordinator = roomNotificationSettingsCoordinator
|
||||
}
|
||||
|
||||
func dismiss(animated: Bool, completion: (() -> Void)?) {
|
||||
guard let coordinator = self.coordinator else {
|
||||
guard let coordinator = coordinator else {
|
||||
return
|
||||
}
|
||||
coordinator.toPresentable().dismiss(animated: animated) {
|
||||
@@ -79,22 +78,21 @@ final class RoomNotificationSettingsCoordinatorBridgePresenter: NSObject {
|
||||
}
|
||||
|
||||
// MARK: - RoomNotificationSettingsCoordinatorDelegate
|
||||
|
||||
extension RoomNotificationSettingsCoordinatorBridgePresenter: RoomNotificationSettingsCoordinatorDelegate {
|
||||
func roomNotificationSettingsCoordinatorDidCancel(_ coordinator: RoomNotificationSettingsCoordinatorType) {
|
||||
self.delegate?.roomNotificationSettingsCoordinatorBridgePresenterDelegateDidComplete(self)
|
||||
delegate?.roomNotificationSettingsCoordinatorBridgePresenterDelegateDidComplete(self)
|
||||
}
|
||||
|
||||
func roomNotificationSettingsCoordinatorDidComplete(_ coordinator: RoomNotificationSettingsCoordinatorType) {
|
||||
self.delegate?.roomNotificationSettingsCoordinatorBridgePresenterDelegateDidComplete(self)
|
||||
delegate?.roomNotificationSettingsCoordinatorBridgePresenterDelegateDidComplete(self)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UIAdaptivePresentationControllerDelegate
|
||||
|
||||
extension RoomNotificationSettingsCoordinatorBridgePresenter: UIAdaptivePresentationControllerDelegate {
|
||||
|
||||
func roomNotificationSettingsCoordinatorDidComplete(_ presentationController: UIPresentationController) {
|
||||
self.delegate?.roomNotificationSettingsCoordinatorBridgePresenterDelegateDidComplete(self)
|
||||
delegate?.roomNotificationSettingsCoordinatorBridgePresenterDelegateDidComplete(self)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+12
-11
@@ -15,14 +15,14 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
final class RoomNotificationSettingsCoordinator: RoomNotificationSettingsCoordinatorType {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var roomNotificationSettingsViewModel: RoomNotificationSettingsViewModelType
|
||||
private let roomNotificationSettingsViewController: UIViewController
|
||||
|
||||
@@ -47,34 +47,35 @@ final class RoomNotificationSettingsCoordinator: RoomNotificationSettingsCoordin
|
||||
roomNotificationService: roomNotificationService,
|
||||
avatarData: avatarData,
|
||||
displayName: room.summary.displayname,
|
||||
roomEncrypted: room.summary.isEncrypted)
|
||||
roomEncrypted: room.summary.isEncrypted
|
||||
)
|
||||
let avatarService: AvatarServiceProtocol = AvatarService(mediaManager: room.mxSession.mediaManager)
|
||||
let view = RoomNotificationSettings(viewModel: viewModel, presentedModally: presentedModally)
|
||||
.addDependency(avatarService)
|
||||
let viewController = VectorHostingController(rootView: view)
|
||||
self.roomNotificationSettingsViewModel = viewModel
|
||||
self.roomNotificationSettingsViewController = viewController
|
||||
roomNotificationSettingsViewModel = viewModel
|
||||
roomNotificationSettingsViewController = viewController
|
||||
}
|
||||
|
||||
// MARK: - Public methods
|
||||
|
||||
func start() {
|
||||
self.roomNotificationSettingsViewModel.coordinatorDelegate = self
|
||||
func start() {
|
||||
roomNotificationSettingsViewModel.coordinatorDelegate = self
|
||||
}
|
||||
|
||||
func toPresentable() -> UIViewController {
|
||||
return self.roomNotificationSettingsViewController
|
||||
roomNotificationSettingsViewController
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - RoomNotificationSettingsViewModelCoordinatorDelegate
|
||||
|
||||
extension RoomNotificationSettingsCoordinator: RoomNotificationSettingsViewModelCoordinatorDelegate {
|
||||
|
||||
func roomNotificationSettingsViewModelDidComplete(_ viewModel: RoomNotificationSettingsViewModelType) {
|
||||
self.delegate?.roomNotificationSettingsCoordinatorDidComplete(self)
|
||||
delegate?.roomNotificationSettingsCoordinatorDidComplete(self)
|
||||
}
|
||||
|
||||
func roomNotificationSettingsViewModelDidCancel(_ viewModel: RoomNotificationSettingsViewModelType) {
|
||||
self.delegate?.roomNotificationSettingsCoordinatorDidCancel(self)
|
||||
delegate?.roomNotificationSettingsCoordinatorDidCancel(self)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -40,4 +40,3 @@ extension RoomNotificationSettingsViewState {
|
||||
roomEncrypted ? VectorL10n.roomNotifsSettingsEncryptedRoomNotice : ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-1
@@ -26,4 +26,3 @@ protocol RoomNotificationSettingsViewStateType {
|
||||
var avatarData: AvatarProtocol? { get }
|
||||
var displayName: String? { get }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -25,7 +25,7 @@ enum RoomNotificationState: Int {
|
||||
extension RoomNotificationState: CaseIterable { }
|
||||
|
||||
extension RoomNotificationState: Identifiable {
|
||||
var id: Int { self.rawValue }
|
||||
var id: Int { rawValue }
|
||||
}
|
||||
|
||||
extension RoomNotificationState {
|
||||
|
||||
+29
-31
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import Foundation
|
||||
|
||||
final class MXRoomNotificationSettingsService: RoomNotificationSettingsServiceType {
|
||||
|
||||
typealias Completion = () -> Void
|
||||
|
||||
// MARK: - Properties
|
||||
@@ -50,11 +49,11 @@ final class MXRoomNotificationSettingsService: RoomNotificationSettingsServiceTy
|
||||
// MARK: - Public
|
||||
|
||||
func observeNotificationState(listener: @escaping RoomNotificationStateCallback) {
|
||||
|
||||
let observer = NotificationCenter.default.addObserver(
|
||||
forName: NSNotification.Name(rawValue: kMXNotificationCenterDidUpdateRules),
|
||||
object: nil,
|
||||
queue: OperationQueue.main) { [weak self] _ in
|
||||
queue: OperationQueue.main
|
||||
) { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
listener(self.room.notificationState)
|
||||
}
|
||||
@@ -88,7 +87,7 @@ final class MXRoomNotificationSettingsService: RoomNotificationSettingsServiceTy
|
||||
}
|
||||
|
||||
guard let rule = room.overridePushRule else {
|
||||
self.addPushRuleToMute(completion: completion)
|
||||
addPushRuleToMute(completion: completion)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -96,7 +95,7 @@ final class MXRoomNotificationSettingsService: RoomNotificationSettingsServiceTy
|
||||
MXLog.debug("[RoomNotificationSettingsService] Request in progress: ignore push rule update")
|
||||
completion()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// if the user defined one, use it
|
||||
if rule.actionsContains(actionType: MXPushRuleActionTypeDontNotify) {
|
||||
@@ -130,7 +129,7 @@ final class MXRoomNotificationSettingsService: RoomNotificationSettingsServiceTy
|
||||
MXLog.debug("[MXRoom+Riot] Request in progress: ignore push rule update")
|
||||
completion()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// if the user defined one, use it
|
||||
if rule.actionsContains(actionType: MXPushRuleActionTypeDontNotify) {
|
||||
@@ -140,11 +139,10 @@ final class MXRoomNotificationSettingsService: RoomNotificationSettingsServiceTy
|
||||
self.addPushRuleToMentionOnly(completion: completion)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private func allMessages(completion: @escaping Completion) {
|
||||
if !room.isMentionsOnly && !room.isMuted {
|
||||
if !room.isMentionsOnly, !room.isMuted {
|
||||
completion()
|
||||
return
|
||||
}
|
||||
@@ -172,7 +170,8 @@ final class MXRoomNotificationSettingsService: RoomNotificationSettingsServiceTy
|
||||
room.roomId,
|
||||
notify: false,
|
||||
sound: false,
|
||||
highlight: false)
|
||||
highlight: false
|
||||
)
|
||||
}
|
||||
|
||||
private func addPushRuleToMute(completion: @escaping Completion) {
|
||||
@@ -207,18 +206,19 @@ final class MXRoomNotificationSettingsService: RoomNotificationSettingsServiceTy
|
||||
private func enablePushRule(rule: MXPushRule, completion: @escaping Completion) {
|
||||
handleUpdateCallback(completion) {
|
||||
// No way to check whether this notification concerns the push rule. Consider the change is applied.
|
||||
return true
|
||||
true
|
||||
}
|
||||
handleFailureCallback(completion)
|
||||
|
||||
room.mxSession.notificationCenter.enableRule(rule, isEnabled: true)
|
||||
}
|
||||
|
||||
private func handleUpdateCallback(_ completion: @escaping Completion, releaseCheck: @escaping () -> Bool) {
|
||||
private func handleUpdateCallback(_ completion: @escaping Completion, releaseCheck: @escaping () -> Bool) {
|
||||
notificationCenterDidUpdateObserver = NotificationCenter.default.addObserver(
|
||||
forName: NSNotification.Name(rawValue: kMXNotificationCenterDidUpdateRules),
|
||||
object: nil,
|
||||
queue: OperationQueue.main) { [weak self] _ in
|
||||
queue: OperationQueue.main
|
||||
) { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
if releaseCheck() {
|
||||
self.removeObservers()
|
||||
@@ -231,7 +231,8 @@ final class MXRoomNotificationSettingsService: RoomNotificationSettingsServiceTy
|
||||
notificationCenterDidFailObserver = NotificationCenter.default.addObserver(
|
||||
forName: NSNotification.Name(rawValue: kMXNotificationCenterDidFailRulesUpdate),
|
||||
object: nil,
|
||||
queue: OperationQueue.main) { [weak self] _ in
|
||||
queue: OperationQueue.main
|
||||
) { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
self.removeObservers()
|
||||
completion()
|
||||
@@ -239,23 +240,23 @@ final class MXRoomNotificationSettingsService: RoomNotificationSettingsServiceTy
|
||||
}
|
||||
|
||||
func removeObservers() {
|
||||
if let observer = self.notificationCenterDidUpdateObserver {
|
||||
if let observer = notificationCenterDidUpdateObserver {
|
||||
NotificationCenter.default.removeObserver(observer)
|
||||
self.notificationCenterDidUpdateObserver = nil
|
||||
notificationCenterDidUpdateObserver = nil
|
||||
}
|
||||
|
||||
if let observer = self.notificationCenterDidFailObserver {
|
||||
if let observer = notificationCenterDidFailObserver {
|
||||
NotificationCenter.default.removeObserver(observer)
|
||||
self.notificationCenterDidFailObserver = nil
|
||||
notificationCenterDidFailObserver = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension MXRoom {
|
||||
public var isMuted: Bool {
|
||||
public extension MXRoom {
|
||||
var isMuted: Bool {
|
||||
// Check whether an override rule has been defined with the roomm id as rule id.
|
||||
// This kind of rule is created to mute the room
|
||||
guard let rule = self.overridePushRule,
|
||||
guard let rule = overridePushRule,
|
||||
rule.actionsContains(actionType: MXPushRuleActionTypeDontNotify),
|
||||
rule.conditionIsEnabled(kind: .eventMatch, for: roomId) else {
|
||||
return false
|
||||
@@ -263,7 +264,7 @@ extension MXRoom {
|
||||
return rule.enabled
|
||||
}
|
||||
|
||||
public var isMentionsOnly: Bool {
|
||||
var isMentionsOnly: Bool {
|
||||
// Check push rules at room level
|
||||
guard let rule = roomPushRule else { return false }
|
||||
return rule.enabled && rule.actionsContains(actionType: MXPushRuleActionTypeDontNotify)
|
||||
@@ -271,8 +272,7 @@ extension MXRoom {
|
||||
}
|
||||
|
||||
// We could move these to their own file and make available in global namespace or move to sdk but they are only used here at the moment
|
||||
fileprivate extension MXRoom {
|
||||
|
||||
private extension MXRoom {
|
||||
typealias Completion = () -> Void
|
||||
func getRoomRule(from rules: [Any]) -> MXPushRule? {
|
||||
guard let pushRules = rules as? [MXPushRule] else {
|
||||
@@ -285,19 +285,18 @@ fileprivate extension MXRoom {
|
||||
var overridePushRule: MXPushRule? {
|
||||
guard let overrideRules = mxSession.notificationCenter.rules.global.override else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return getRoomRule(from: overrideRules)
|
||||
}
|
||||
|
||||
var roomPushRule: MXPushRule? {
|
||||
guard let roomRules = mxSession.notificationCenter.rules.global.room else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return getRoomRule(from: roomRules)
|
||||
}
|
||||
|
||||
var notificationState: RoomNotificationState {
|
||||
|
||||
if isMuted {
|
||||
return .mute
|
||||
}
|
||||
@@ -306,10 +305,9 @@ fileprivate extension MXRoom {
|
||||
}
|
||||
return .all
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fileprivate extension MXPushRule {
|
||||
private extension MXPushRule {
|
||||
func actionsContains(actionType: MXPushRuleActionType) -> Bool {
|
||||
guard let actions = actions as? [MXPushRuleAction] else {
|
||||
return false
|
||||
@@ -323,8 +321,8 @@ fileprivate extension MXPushRule {
|
||||
}
|
||||
let ruleContainsCondition = conditions.contains { condition in
|
||||
guard case kind = MXPushRuleConditionType(identifier: condition.kind),
|
||||
let key = condition.parameters["key"] as? String,
|
||||
let pattern = condition.parameters["pattern"] as? String
|
||||
let key = condition.parameters["key"] as? String,
|
||||
let pattern = condition.parameters["pattern"] as? String
|
||||
else { return false }
|
||||
return key == "room_id" && pattern == roomId
|
||||
}
|
||||
|
||||
+2
-3
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import Foundation
|
||||
|
||||
class MockRoomNotificationSettingsService: RoomNotificationSettingsServiceType {
|
||||
|
||||
static let example = MockRoomNotificationSettingsService(initialState: .all)
|
||||
|
||||
var listener: RoomNotificationStateCallback?
|
||||
@@ -32,7 +31,7 @@ class MockRoomNotificationSettingsService: RoomNotificationSettingsServiceType {
|
||||
}
|
||||
|
||||
func update(state: RoomNotificationState, completion: @escaping UpdateRoomNotificationStateCompletion) {
|
||||
self.notificationState = state
|
||||
notificationState = state
|
||||
completion()
|
||||
listener?(state)
|
||||
}
|
||||
|
||||
+1
-2
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -20,7 +20,6 @@ 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 }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct FormPickerItem: View {
|
||||
|
||||
typealias TapCallback = () -> Void
|
||||
|
||||
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||
@@ -53,7 +52,6 @@ struct FormPickerItem: View {
|
||||
}
|
||||
|
||||
struct FormPickerItem_Previews: PreviewProvider {
|
||||
|
||||
static let items = ["Item 1", "Item 2", "Item 3"]
|
||||
static var selected: String = items[0]
|
||||
static var previews: some View {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct FormSectionFooter: View {
|
||||
|
||||
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||
var text: String
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct FormSectionHeader: View {
|
||||
|
||||
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||
var text: String
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct RoomNotificationSettings: View {
|
||||
|
||||
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||
|
||||
@ObservedObject var viewModel: RoomNotificationSettingsSwiftUIViewModel
|
||||
@@ -42,7 +41,7 @@ struct RoomNotificationSettings: View {
|
||||
|
||||
var body: some View {
|
||||
VectorForm {
|
||||
if let avatarData = viewModel.viewState.avatarData as? AvatarInputProtocol {
|
||||
if let avatarData = viewModel.viewState.avatarData as? AvatarInputProtocol {
|
||||
RoomNotificationSettingsHeader(
|
||||
avatarData: avatarData,
|
||||
displayName: viewModel.viewState.displayName
|
||||
@@ -74,7 +73,6 @@ struct RoomNotificationSettings: View {
|
||||
}
|
||||
|
||||
struct RoomNotificationSettings_Previews: PreviewProvider {
|
||||
|
||||
static let mockViewModel = RoomNotificationSettingsSwiftUIViewModel(
|
||||
roomNotificationService: MockRoomNotificationSettingsService.example,
|
||||
avatarData: MockAvatarInput.example,
|
||||
|
||||
+1
-2
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct RoomNotificationSettingsHeader: View {
|
||||
|
||||
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||
var avatarData: AvatarInputProtocol
|
||||
var displayName: String?
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct VectorForm<Content: View>: View {
|
||||
|
||||
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||
var content: () -> Content
|
||||
|
||||
@@ -38,12 +37,10 @@ struct VectorForm<Content: View>: View {
|
||||
)
|
||||
.background(theme.colors.system)
|
||||
.edgesIgnoringSafeArea(.bottom)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
struct VectorForm_Previews: PreviewProvider {
|
||||
|
||||
static var previews: some View {
|
||||
Group {
|
||||
VectorForm {
|
||||
|
||||
+3
-4
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,17 +14,16 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
class RoomNotificationSettingsSwiftUIViewModel: RoomNotificationSettingsViewModel, ObservableObject {
|
||||
|
||||
@Published var viewState: RoomNotificationSettingsViewState
|
||||
|
||||
lazy var cancellables = Set<AnyCancellable>()
|
||||
|
||||
override init(roomNotificationService: RoomNotificationSettingsServiceType, initialState: RoomNotificationSettingsViewState) {
|
||||
self.viewState = initialState
|
||||
viewState = initialState
|
||||
super.init(roomNotificationService: roomNotificationService, initialState: initialState)
|
||||
}
|
||||
|
||||
|
||||
+12
-17
@@ -16,11 +16,10 @@
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModelType {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -40,12 +39,10 @@ class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModelType {
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
init(
|
||||
roomNotificationService: RoomNotificationSettingsServiceType,
|
||||
initialState: RoomNotificationSettingsViewState
|
||||
) {
|
||||
init(roomNotificationService: RoomNotificationSettingsServiceType,
|
||||
initialState: RoomNotificationSettingsViewState) {
|
||||
self.roomNotificationService = roomNotificationService
|
||||
self.state = initialState
|
||||
state = initialState
|
||||
|
||||
self.roomNotificationService.observeNotificationState { [weak self] state in
|
||||
guard let self = self else { return }
|
||||
@@ -53,12 +50,10 @@ class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModelType {
|
||||
}
|
||||
}
|
||||
|
||||
convenience init(
|
||||
roomNotificationService: RoomNotificationSettingsServiceType,
|
||||
avatarData: AvatarProtocol?,
|
||||
displayName: String?,
|
||||
roomEncrypted: Bool
|
||||
) {
|
||||
convenience init(roomNotificationService: RoomNotificationSettingsServiceType,
|
||||
avatarData: AvatarProtocol?,
|
||||
displayName: String?,
|
||||
roomEncrypted: Bool) {
|
||||
let notificationState = Self.mapNotificationStateOnRead(encrypted: roomEncrypted, state: roomNotificationService.notificationState)
|
||||
|
||||
let initialState = RoomNotificationSettingsViewState(
|
||||
@@ -71,16 +66,16 @@ class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModelType {
|
||||
self.init(roomNotificationService: roomNotificationService, initialState: initialState)
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
// MARK: - Public
|
||||
|
||||
func process(viewAction: RoomNotificationSettingsViewAction) {
|
||||
switch viewAction {
|
||||
case .load:
|
||||
update(viewState: self.state)
|
||||
update(viewState: state)
|
||||
case .selectNotificationState(let state):
|
||||
self.state.notificationState = state
|
||||
case .save:
|
||||
self.state.saving = true
|
||||
state.saving = true
|
||||
roomNotificationService.update(state: state.notificationState) { [weak self] in
|
||||
guard let self = self else { return }
|
||||
self.state.saving = false
|
||||
@@ -103,6 +98,6 @@ class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModelType {
|
||||
}
|
||||
|
||||
func update(viewState: RoomNotificationSettingsViewState) {
|
||||
self.viewDelegate?.roomNotificationSettingsViewModel(self, didUpdateViewState: viewState)
|
||||
viewDelegate?.roomNotificationSettingsViewModel(self, didUpdateViewState: viewState)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -28,8 +28,7 @@ protocol RoomNotificationSettingsViewModelCoordinatorDelegate: AnyObject {
|
||||
}
|
||||
|
||||
/// Protocol describing the view model used by `RoomNotificationSettingsViewController`
|
||||
protocol RoomNotificationSettingsViewModelType {
|
||||
|
||||
protocol RoomNotificationSettingsViewModelType {
|
||||
var viewDelegate: RoomNotificationSettingsViewModelViewDelegate? { get set }
|
||||
var coordinatorDelegate: RoomNotificationSettingsViewModelCoordinatorDelegate? { get set }
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
struct PollEditFormCoordinatorParameters {
|
||||
let room: MXRoom
|
||||
@@ -24,7 +24,6 @@ struct PollEditFormCoordinatorParameters {
|
||||
}
|
||||
|
||||
final class PollEditFormCoordinator: Coordinator, Presentable {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -50,7 +49,7 @@ final class PollEditFormCoordinator: Coordinator, Presentable {
|
||||
viewModel = PollEditFormViewModel(parameters: PollEditFormViewModelParameters(mode: .editing,
|
||||
pollDetails: EditFormPollDetails(type: Self.pollKindKeyToDetailsType(pollContent.kind),
|
||||
question: pollContent.question,
|
||||
answerOptions: pollContent.answerOptions.map { $0.text })))
|
||||
answerOptions: pollContent.answerOptions.map(\.text))))
|
||||
|
||||
} else {
|
||||
viewModel = PollEditFormViewModel(parameters: PollEditFormViewModelParameters(mode: .creation, pollDetails: .default))
|
||||
@@ -63,6 +62,7 @@ final class PollEditFormCoordinator: Coordinator, Presentable {
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
func start() {
|
||||
pollEditFormViewModel.completion = { [weak self] result in
|
||||
guard let self = self else { return }
|
||||
@@ -75,7 +75,7 @@ final class PollEditFormCoordinator: Coordinator, Presentable {
|
||||
|
||||
self.pollEditFormViewModel.startLoading()
|
||||
|
||||
self.parameters.room.sendPollStart(withContent: pollStartContent, threadId: nil, localEcho: nil) { [weak self] result in
|
||||
self.parameters.room.sendPollStart(withContent: pollStartContent, threadId: nil, localEcho: nil) { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
|
||||
self.pollEditFormViewModel.stopLoading()
|
||||
@@ -103,7 +103,7 @@ final class PollEditFormCoordinator: Coordinator, Presentable {
|
||||
|
||||
self.parameters.room.sendPollUpdate(for: pollStartEvent,
|
||||
oldContent: oldPollContent,
|
||||
newContent: newPollContent, localEcho: nil) { [weak self] result in
|
||||
newContent: newPollContent, localEcho: nil) { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
|
||||
self.pollEditFormViewModel.stopLoading()
|
||||
@@ -113,7 +113,7 @@ final class PollEditFormCoordinator: Coordinator, Presentable {
|
||||
|
||||
MXLog.error("Failed updating poll", context: error)
|
||||
self.pollEditFormViewModel.stopLoading(errorAlertType: .failedUpdatingPoll)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,7 +121,7 @@ final class PollEditFormCoordinator: Coordinator, Presentable {
|
||||
// MARK: - Presentable
|
||||
|
||||
func toPresentable() -> UIViewController {
|
||||
return pollEditFormHostingController
|
||||
pollEditFormHostingController
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
@@ -136,21 +136,20 @@ final class PollEditFormCoordinator: Coordinator, Presentable {
|
||||
kind: Self.pollDetailsTypeToKindKey(details.type),
|
||||
maxSelections: NSNumber(value: details.maxSelections),
|
||||
answerOptions: options)
|
||||
|
||||
}
|
||||
|
||||
private static func pollDetailsTypeToKindKey(_ type: EditFormPollType) -> String {
|
||||
let mapping = [EditFormPollType.disclosed : kMXMessageContentKeyExtensiblePollKindDisclosedMSC3381,
|
||||
EditFormPollType.undisclosed : kMXMessageContentKeyExtensiblePollKindUndisclosedMSC3381]
|
||||
let mapping = [EditFormPollType.disclosed: kMXMessageContentKeyExtensiblePollKindDisclosedMSC3381,
|
||||
EditFormPollType.undisclosed: kMXMessageContentKeyExtensiblePollKindUndisclosedMSC3381]
|
||||
|
||||
return mapping[type] ?? kMXMessageContentKeyExtensiblePollKindDisclosedMSC3381
|
||||
}
|
||||
|
||||
private static func pollKindKeyToDetailsType(_ key: String) -> EditFormPollType {
|
||||
let mapping = [kMXMessageContentKeyExtensiblePollKindDisclosed : EditFormPollType.disclosed,
|
||||
kMXMessageContentKeyExtensiblePollKindDisclosedMSC3381 : EditFormPollType.disclosed,
|
||||
kMXMessageContentKeyExtensiblePollKindUndisclosed : EditFormPollType.undisclosed,
|
||||
kMXMessageContentKeyExtensiblePollKindUndisclosedMSC3381 : EditFormPollType.undisclosed]
|
||||
let mapping = [kMXMessageContentKeyExtensiblePollKindDisclosed: EditFormPollType.disclosed,
|
||||
kMXMessageContentKeyExtensiblePollKindDisclosedMSC3381: EditFormPollType.disclosed,
|
||||
kMXMessageContentKeyExtensiblePollKindUndisclosed: EditFormPollType.undisclosed,
|
||||
kMXMessageContentKeyExtensiblePollKindUndisclosedMSC3381: EditFormPollType.undisclosed]
|
||||
|
||||
return mapping[key] ?? EditFormPollType.disclosed
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -82,14 +82,14 @@ struct PollEditFormViewState: BindableState {
|
||||
|
||||
var confirmationButtonEnabled: Bool {
|
||||
!bindings.question.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty &&
|
||||
bindings.answerOptions.filter({ !$0.text.isEmpty }).count >= minAnswerOptionsCount
|
||||
bindings.answerOptions.filter { !$0.text.isEmpty }.count >= minAnswerOptionsCount
|
||||
}
|
||||
|
||||
var addAnswerOptionButtonEnabled: Bool {
|
||||
bindings.answerOptions.count < maxAnswerOptionsCount
|
||||
}
|
||||
|
||||
var showLoadingIndicator: Bool = false
|
||||
var showLoadingIndicator = false
|
||||
}
|
||||
|
||||
struct PollEditFormViewStateBindings {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -24,7 +24,7 @@ enum MockPollEditFormScreenState: MockScreenState, CaseIterable {
|
||||
PollEditForm.self
|
||||
}
|
||||
|
||||
var screenView: ([Any], AnyView) {
|
||||
var screenView: ([Any], AnyView) {
|
||||
let viewModel = PollEditFormViewModel(parameters: PollEditFormViewModelParameters(mode: .creation, pollDetails: .default))
|
||||
return ([viewModel], AnyView(PollEditForm(viewModel: viewModel.context)))
|
||||
}
|
||||
|
||||
@@ -14,20 +14,19 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
struct PollEditFormViewModelParameters {
|
||||
let mode: PollEditFormMode
|
||||
let pollDetails: EditFormPollDetails
|
||||
}
|
||||
|
||||
typealias PollEditFormViewModelType = StateStoreViewModel <PollEditFormViewState,
|
||||
Never,
|
||||
PollEditFormViewAction>
|
||||
typealias PollEditFormViewModelType = StateStoreViewModel<PollEditFormViewState,
|
||||
Never,
|
||||
PollEditFormViewAction>
|
||||
class PollEditFormViewModel: PollEditFormViewModelType, PollEditFormViewModelProtocol {
|
||||
|
||||
private struct Constants {
|
||||
private enum Constants {
|
||||
static let minAnswerOptionsCount = 2
|
||||
static let maxAnswerOptionsCount = 20
|
||||
static let maxQuestionLength = 340
|
||||
@@ -102,11 +101,11 @@ class PollEditFormViewModel: PollEditFormViewModelType, PollEditFormViewModelPro
|
||||
// MARK: - Private
|
||||
|
||||
private func buildPollDetails() -> EditFormPollDetails {
|
||||
return EditFormPollDetails(type: state.bindings.type,
|
||||
question: state.bindings.question.text.trimmingCharacters(in: .whitespacesAndNewlines),
|
||||
answerOptions: state.bindings.answerOptions.compactMap({ answerOption in
|
||||
let text = answerOption.text.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
return text.isEmpty ? nil : text
|
||||
}))
|
||||
EditFormPollDetails(type: state.bindings.type,
|
||||
question: state.bindings.question.text.trimmingCharacters(in: .whitespacesAndNewlines),
|
||||
answerOptions: state.bindings.answerOptions.compactMap { answerOption in
|
||||
let text = answerOption.text.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
return text.isEmpty ? nil : text
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import RiotSwiftUI
|
||||
import XCTest
|
||||
|
||||
class PollEditFormUITests: MockScreenTestCase {
|
||||
func testInitialStateComponents() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,8 +14,8 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Combine
|
||||
import XCTest
|
||||
|
||||
@testable import RiotSwiftUI
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct PollEditForm: View {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -33,7 +32,6 @@ struct PollEditForm: View {
|
||||
GeometryReader { proxy in
|
||||
ScrollView {
|
||||
VStack(alignment: .leading, spacing: 32.0) {
|
||||
|
||||
PollEditFormTypePicker(selectedType: $viewModel.type)
|
||||
|
||||
VStack(alignment: .leading, spacing: 16.0) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct PollEditFormAnswerOptionView: View {
|
||||
|
||||
@Environment(\.theme) private var theme: ThemeSwiftUI
|
||||
|
||||
@State private var focused = false
|
||||
@@ -39,7 +38,7 @@ struct PollEditFormAnswerOptionView: View {
|
||||
})
|
||||
.textFieldStyle(BorderedInputFieldStyle(isEditing: focused))
|
||||
Button(action: onDelete) {
|
||||
Image(uiImage:Asset.Images.pollDeleteOptionIcon.image)
|
||||
Image(uiImage: Asset.Images.pollDeleteOptionIcon.image)
|
||||
}
|
||||
.accessibilityIdentifier("Delete answer option")
|
||||
}
|
||||
@@ -50,12 +49,8 @@ struct PollEditFormAnswerOptionView: View {
|
||||
struct PollEditFormAnswerOptionView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
VStack(spacing: 32.0) {
|
||||
PollEditFormAnswerOptionView(text: Binding.constant(""), index: 0) {
|
||||
|
||||
}
|
||||
PollEditFormAnswerOptionView(text: Binding.constant("Test"), index: 5) {
|
||||
|
||||
}
|
||||
PollEditFormAnswerOptionView(text: Binding.constant(""), index: 0) { }
|
||||
PollEditFormAnswerOptionView(text: Binding.constant("Test"), index: 5) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -43,7 +43,6 @@ private struct PollEditFormTypeButton: View {
|
||||
selectedType = type
|
||||
} label: {
|
||||
HStack(alignment: .top, spacing: 8.0) {
|
||||
|
||||
Image(uiImage: selectionImage)
|
||||
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
|
||||
@@ -26,7 +26,6 @@ enum RoomAccessCoordinatorCoordinatorAction {
|
||||
|
||||
@objcMembers
|
||||
final class RoomAccessCoordinator: Coordinator {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -35,7 +34,7 @@ final class RoomAccessCoordinator: Coordinator {
|
||||
private var upgradedRoomId: String?
|
||||
|
||||
private var navigationRouter: NavigationRouterType {
|
||||
return self.parameters.navigationRouter
|
||||
parameters.navigationRouter
|
||||
}
|
||||
|
||||
// MARK: Public
|
||||
@@ -58,32 +57,31 @@ final class RoomAccessCoordinator: Coordinator {
|
||||
|
||||
init(parameters: RoomAccessCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
|
||||
func start() {
|
||||
MXLog.debug("[RoomAccessCoordinator] did start.")
|
||||
let rootCoordinator = self.createRoomAccessTypeCoordinator()
|
||||
let rootCoordinator = createRoomAccessTypeCoordinator()
|
||||
rootCoordinator.start()
|
||||
|
||||
self.add(childCoordinator: rootCoordinator)
|
||||
self.accessCoordinator = rootCoordinator
|
||||
add(childCoordinator: rootCoordinator)
|
||||
accessCoordinator = rootCoordinator
|
||||
|
||||
if self.navigationRouter.modules.isEmpty == false {
|
||||
self.navigationRouter.push(rootCoordinator, animated: true, popCompletion: { [weak self] in
|
||||
if navigationRouter.modules.isEmpty == false {
|
||||
navigationRouter.push(rootCoordinator, animated: true, popCompletion: { [weak self] in
|
||||
self?.remove(childCoordinator: rootCoordinator)
|
||||
})
|
||||
} else {
|
||||
self.navigationRouter.setRootModule(rootCoordinator) { [weak self] in
|
||||
navigationRouter.setRootModule(rootCoordinator) { [weak self] in
|
||||
self?.remove(childCoordinator: rootCoordinator)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func toPresentable() -> UIViewController {
|
||||
return self.navigationRouter.toPresentable()
|
||||
navigationRouter.toPresentable()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
@@ -91,7 +89,7 @@ final class RoomAccessCoordinator: Coordinator {
|
||||
func pushScreen(with coordinator: Coordinator & Presentable) {
|
||||
add(childCoordinator: coordinator)
|
||||
|
||||
self.navigationRouter.push(coordinator, animated: true, popCompletion: { [weak self] in
|
||||
navigationRouter.push(coordinator, animated: true, popCompletion: { [weak self] in
|
||||
self?.remove(childCoordinator: coordinator)
|
||||
})
|
||||
|
||||
@@ -103,13 +101,13 @@ final class RoomAccessCoordinator: Coordinator {
|
||||
|
||||
coordinator.toPresentable().modalPresentationStyle = .overFullScreen
|
||||
coordinator.toPresentable().modalTransitionStyle = .crossDissolve
|
||||
self.navigationRouter.present(coordinator, animated: true)
|
||||
navigationRouter.present(coordinator, animated: true)
|
||||
|
||||
coordinator.start()
|
||||
}
|
||||
|
||||
private func createRoomAccessTypeCoordinator() -> RoomAccessTypeChooserCoordinator {
|
||||
let coordinator: RoomAccessTypeChooserCoordinator = RoomAccessTypeChooserCoordinator(parameters: RoomAccessTypeChooserCoordinatorParameters(roomId: parameters.room.roomId, allowsRoomUpgrade: parameters.allowsRoomUpgrade, session: parameters.room.mxSession))
|
||||
let coordinator = RoomAccessTypeChooserCoordinator(parameters: RoomAccessTypeChooserCoordinatorParameters(roomId: parameters.room.roomId, allowsRoomUpgrade: parameters.allowsRoomUpgrade, session: parameters.room.mxSession))
|
||||
coordinator.callback = { [weak self] result in
|
||||
guard let self = self else { return }
|
||||
|
||||
@@ -132,7 +130,8 @@ final class RoomAccessCoordinator: Coordinator {
|
||||
let paramaters = MatrixItemChooserCoordinatorParameters(
|
||||
session: parameters.room.mxSession,
|
||||
viewProvider: RoomRestrictedAccessSpaceChooserViewProvider(navTitle: VectorL10n.roomAccessSettingsScreenNavTitle),
|
||||
itemsProcessor: RoomRestrictedAccessSpaceChooserItemsProcessor(roomId: roomId, session: parameters.room.mxSession))
|
||||
itemsProcessor: RoomRestrictedAccessSpaceChooserItemsProcessor(roomId: roomId, session: parameters.room.mxSession)
|
||||
)
|
||||
let coordinator = MatrixItemChooserCoordinator(parameters: paramaters)
|
||||
coordinator.completion = { [weak self] result in
|
||||
guard let self = self else { return }
|
||||
@@ -154,7 +153,8 @@ final class RoomAccessCoordinator: Coordinator {
|
||||
session: parameters.room.mxSession,
|
||||
roomId: roomId,
|
||||
parentSpaceId: parameters.parentSpaceId,
|
||||
versionOverride: versionOverride)
|
||||
versionOverride: versionOverride
|
||||
)
|
||||
let coordinator = RoomUpgradeCoordinator(parameters: paramaters)
|
||||
|
||||
coordinator.completion = { [weak self] result in
|
||||
|
||||
+5
-8
@@ -1,4 +1,5 @@
|
||||
//
|
||||
import MatrixSDK
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,7 +15,6 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
import UIKit
|
||||
import MatrixSDK
|
||||
|
||||
@objc protocol RoomAccessCoordinatorBridgePresenterDelegate {
|
||||
func roomAccessCoordinatorBridgePresenterDelegate(_ coordinatorBridgePresenter: RoomAccessCoordinatorBridgePresenter, didCancelRoomWithId roomId: String)
|
||||
@@ -27,7 +27,6 @@ import MatrixSDK
|
||||
/// Each bridge should be removed once the underlying Coordinator has been integrated by another Coordinator.
|
||||
@objcMembers
|
||||
final class RoomAccessCoordinatorBridgePresenter: NSObject {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -82,7 +81,7 @@ final class RoomAccessCoordinatorBridgePresenter: NSObject {
|
||||
}
|
||||
|
||||
func dismiss(animated: Bool, completion: (() -> Void)?) {
|
||||
guard let coordinator = self.coordinator else {
|
||||
guard let coordinator = coordinator else {
|
||||
return
|
||||
}
|
||||
coordinator.toPresentable().dismiss(animated: animated) {
|
||||
@@ -98,13 +97,11 @@ final class RoomAccessCoordinatorBridgePresenter: NSObject {
|
||||
// MARK: - UIAdaptivePresentationControllerDelegate
|
||||
|
||||
extension RoomAccessCoordinatorBridgePresenter: UIAdaptivePresentationControllerDelegate {
|
||||
|
||||
func roomNotificationSettingsCoordinatorDidComplete(_ presentationController: UIPresentationController) {
|
||||
if let roomId = self.coordinator?.currentRoomId {
|
||||
self.delegate?.roomAccessCoordinatorBridgePresenterDelegate(self, didCancelRoomWithId: roomId)
|
||||
if let roomId = coordinator?.currentRoomId {
|
||||
delegate?.roomAccessCoordinatorBridgePresenterDelegate(self, didCancelRoomWithId: roomId)
|
||||
} else {
|
||||
self.delegate?.roomAccessCoordinatorBridgePresenterDelegate(self, didCancelRoomWithId: self.room.roomId)
|
||||
delegate?.roomAccessCoordinatorBridgePresenterDelegate(self, didCancelRoomWithId: room.roomId)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import Foundation
|
||||
|
||||
/// RoomAccessCoordinator input parameters
|
||||
struct RoomAccessCoordinatorParameters {
|
||||
|
||||
/// The Matrix room
|
||||
let room: MXRoom
|
||||
|
||||
|
||||
+2
-3
@@ -23,7 +23,6 @@ struct RoomAccessTypeChooserCoordinatorParameters {
|
||||
}
|
||||
|
||||
final class RoomAccessTypeChooserCoordinator: Coordinator, Presentable {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -70,10 +69,10 @@ final class RoomAccessTypeChooserCoordinator: Coordinator, Presentable {
|
||||
}
|
||||
|
||||
func toPresentable() -> UIViewController {
|
||||
return self.roomAccessTypeChooserHostingController
|
||||
roomAccessTypeChooserHostingController
|
||||
}
|
||||
|
||||
func handleRoomUpgradeResult(_ result: RoomUpgradeCoordinatorResult) {
|
||||
self.roomAccessTypeChooserViewModel.handleRoomUpgradeResult(result)
|
||||
roomAccessTypeChooserViewModel.handleRoomUpgradeResult(result)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-3
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
|
||||
/// Using an enum for the screen allows you define the different state cases with
|
||||
/// the relevant associated data for each case.
|
||||
enum MockRoomAccessTypeChooserScreenState: MockScreenState, CaseIterable {
|
||||
@@ -42,7 +41,7 @@ enum MockRoomAccessTypeChooserScreenState: MockScreenState, CaseIterable {
|
||||
service = MockRoomAccessTypeChooserService(accessItems: [
|
||||
RoomAccessTypeChooserAccessItem(id: .private, isSelected: true, title: VectorL10n.private, detail: VectorL10n.roomAccessSettingsScreenPrivateMessage, badgeText: nil),
|
||||
RoomAccessTypeChooserAccessItem(id: .restricted, isSelected: false, title: VectorL10n.createRoomTypeRestricted, detail: VectorL10n.roomAccessSettingsScreenRestrictedMessage, badgeText: VectorL10n.roomAccessSettingsScreenUpgradeRequired),
|
||||
RoomAccessTypeChooserAccessItem(id: .public, isSelected: false, title: VectorL10n.public, detail: VectorL10n.roomAccessSettingsScreenPublicMessage, badgeText: nil),
|
||||
RoomAccessTypeChooserAccessItem(id: .public, isSelected: false, title: VectorL10n.public, detail: VectorL10n.roomAccessSettingsScreenPublicMessage, badgeText: nil)
|
||||
])
|
||||
}
|
||||
let viewModel = RoomAccessTypeChooserViewModel(roomAccessTypeChooserService: service)
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
+7
-7
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,14 +14,13 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
typealias RoomAccessTypeChooserViewModelType = StateStoreViewModel<RoomAccessTypeChooserViewState,
|
||||
RoomAccessTypeChooserStateAction,
|
||||
RoomAccessTypeChooserViewAction>
|
||||
RoomAccessTypeChooserStateAction,
|
||||
RoomAccessTypeChooserViewAction>
|
||||
class RoomAccessTypeChooserViewModel: RoomAccessTypeChooserViewModelType, RoomAccessTypeChooserViewModelProtocol {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -43,7 +42,8 @@ class RoomAccessTypeChooserViewModel: RoomAccessTypeChooserViewModelType, RoomAc
|
||||
private static func defaultState(roomAccessTypeChooserService: RoomAccessTypeChooserServiceProtocol) -> RoomAccessTypeChooserViewState {
|
||||
let bindings = RoomAccessTypeChooserViewModelBindings(
|
||||
showUpgradeRoomAlert: roomAccessTypeChooserService.roomUpgradeRequiredSubject.value,
|
||||
waitingMessage: roomAccessTypeChooserService.waitingMessageSubject.value, isLoading: roomAccessTypeChooserService.waitingMessageSubject.value != nil)
|
||||
waitingMessage: roomAccessTypeChooserService.waitingMessageSubject.value, isLoading: roomAccessTypeChooserService.waitingMessageSubject.value != nil
|
||||
)
|
||||
return RoomAccessTypeChooserViewState(accessItems: roomAccessTypeChooserService.accessItemsSubject.value, bindings: bindings)
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ class RoomAccessTypeChooserViewModel: RoomAccessTypeChooserViewModelType, RoomAc
|
||||
|
||||
private func didSelect(accessType: RoomAccessTypeChooserAccessType) {
|
||||
roomAccessTypeChooserService.updateSelection(with: accessType)
|
||||
if accessType == .restricted && !roomAccessTypeChooserService.roomUpgradeRequiredSubject.value {
|
||||
if accessType == .restricted, !roomAccessTypeChooserService.roomUpgradeRequiredSubject.value {
|
||||
callback?(.spaceSelection(roomAccessTypeChooserService.currentRoomId, .restricted))
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
+15
-14
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,12 +14,11 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Foundation
|
||||
import MatrixSDK
|
||||
|
||||
class RoomAccessTypeChooserService: RoomAccessTypeChooserServiceProtocol {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -40,6 +39,7 @@ class RoomAccessTypeChooserService: RoomAccessTypeChooserServiceProtocol {
|
||||
accessItemsSubject.send(accessItems)
|
||||
}
|
||||
}
|
||||
|
||||
private(set) var selectedType: RoomAccessTypeChooserAccessType = .private {
|
||||
didSet {
|
||||
for (index, item) in accessItems.enumerated() {
|
||||
@@ -48,6 +48,7 @@ class RoomAccessTypeChooserService: RoomAccessTypeChooserServiceProtocol {
|
||||
accessItemsSubject.send(accessItems)
|
||||
}
|
||||
}
|
||||
|
||||
private var roomJoinRule: MXRoomJoinRule = .private
|
||||
private var currentOperation: MXHTTPOperation?
|
||||
|
||||
@@ -67,8 +68,8 @@ class RoomAccessTypeChooserService: RoomAccessTypeChooserServiceProtocol {
|
||||
self.roomId = roomId
|
||||
self.allowsRoomUpgrade = allowsRoomUpgrade
|
||||
self.session = session
|
||||
self.currentRoomId = roomId
|
||||
self.versionOverride = session.homeserverCapabilitiesService.versionOverrideForFeature(.restricted)
|
||||
currentRoomId = roomId
|
||||
versionOverride = session.homeserverCapabilitiesService.versionOverrideForFeature(.restricted)
|
||||
|
||||
roomUpgradeRequiredSubject = CurrentValueSubject(false)
|
||||
waitingMessageSubject = CurrentValueSubject(nil)
|
||||
@@ -92,7 +93,7 @@ class RoomAccessTypeChooserService: RoomAccessTypeChooserServiceProtocol {
|
||||
self.selectedType = selectedType
|
||||
|
||||
if selectedType == .restricted {
|
||||
if roomUpgradeRequired && roomUpgradeRequiredSubject.value == false {
|
||||
if roomUpgradeRequired, roomUpgradeRequiredSubject.value == false {
|
||||
roomUpgradeRequiredSubject.send(true)
|
||||
}
|
||||
}
|
||||
@@ -108,14 +109,14 @@ class RoomAccessTypeChooserService: RoomAccessTypeChooserServiceProtocol {
|
||||
|
||||
let _joinRule: MXRoomJoinRule?
|
||||
|
||||
switch self.selectedType {
|
||||
switch selectedType {
|
||||
case .private:
|
||||
_joinRule = .invite
|
||||
case .public:
|
||||
_joinRule = .public
|
||||
case .restricted:
|
||||
_joinRule = nil
|
||||
if roomUpgradeRequired && roomUpgradeRequiredSubject.value == false {
|
||||
if roomUpgradeRequired, roomUpgradeRequiredSubject.value == false {
|
||||
roomUpgradeRequiredSubject.send(true)
|
||||
} else {
|
||||
completion()
|
||||
@@ -123,7 +124,7 @@ class RoomAccessTypeChooserService: RoomAccessTypeChooserServiceProtocol {
|
||||
}
|
||||
|
||||
if let joinRule = _joinRule {
|
||||
self.waitingMessageSubject.send(VectorL10n.roomAccessSettingsScreenSettingRoomAccess)
|
||||
waitingMessageSubject.send(VectorL10n.roomAccessSettingsScreenSettingRoomAccess)
|
||||
|
||||
room.setJoinRule(joinRule) { [weak self] response in
|
||||
guard let self = self else { return }
|
||||
@@ -140,7 +141,7 @@ class RoomAccessTypeChooserService: RoomAccessTypeChooserServiceProtocol {
|
||||
}
|
||||
|
||||
func updateRoomId(with roomId: String) {
|
||||
self.currentRoomId = roomId
|
||||
currentRoomId = roomId
|
||||
readRoomState()
|
||||
}
|
||||
|
||||
@@ -148,17 +149,17 @@ class RoomAccessTypeChooserService: RoomAccessTypeChooserServiceProtocol {
|
||||
|
||||
private func setupAccessItems() {
|
||||
guard let spaceService = session.spaceService, let ancestors = spaceService.ancestorsPerRoomId[currentRoomId], !ancestors.isEmpty, allowsRoomUpgrade || !roomUpgradeRequired else {
|
||||
self.accessItems = [
|
||||
accessItems = [
|
||||
RoomAccessTypeChooserAccessItem(id: .private, isSelected: false, title: VectorL10n.private, detail: VectorL10n.roomAccessSettingsScreenPrivateMessage, badgeText: nil),
|
||||
RoomAccessTypeChooserAccessItem(id: .public, isSelected: false, title: VectorL10n.public, detail: VectorL10n.roomAccessSettingsScreenPublicMessage, badgeText: nil),
|
||||
RoomAccessTypeChooserAccessItem(id: .public, isSelected: false, title: VectorL10n.public, detail: VectorL10n.roomAccessSettingsScreenPublicMessage, badgeText: nil)
|
||||
]
|
||||
return
|
||||
}
|
||||
|
||||
self.accessItems = [
|
||||
accessItems = [
|
||||
RoomAccessTypeChooserAccessItem(id: .private, isSelected: false, title: VectorL10n.private, detail: VectorL10n.roomAccessSettingsScreenPrivateMessage, badgeText: nil),
|
||||
RoomAccessTypeChooserAccessItem(id: .restricted, isSelected: false, title: VectorL10n.createRoomTypeRestricted, detail: VectorL10n.roomAccessSettingsScreenRestrictedMessage, badgeText: roomUpgradeRequired ? VectorL10n.roomAccessSettingsScreenUpgradeRequired : VectorL10n.roomAccessSettingsScreenEditSpaces),
|
||||
RoomAccessTypeChooserAccessItem(id: .public, isSelected: false, title: VectorL10n.public, detail: VectorL10n.roomAccessSettingsScreenPublicMessage, badgeText: nil),
|
||||
RoomAccessTypeChooserAccessItem(id: .public, isSelected: false, title: VectorL10n.public, detail: VectorL10n.roomAccessSettingsScreenPublicMessage, badgeText: nil)
|
||||
]
|
||||
|
||||
accessItemsSubject.send(accessItems)
|
||||
|
||||
+8
-13
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,15 +14,14 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
class MockRoomAccessTypeChooserService: RoomAccessTypeChooserServiceProtocol {
|
||||
|
||||
static let mockAccessItems: [RoomAccessTypeChooserAccessItem] = [
|
||||
RoomAccessTypeChooserAccessItem(id: .private, isSelected: true, title: VectorL10n.private, detail: VectorL10n.roomAccessSettingsScreenPrivateMessage, badgeText: nil),
|
||||
RoomAccessTypeChooserAccessItem(id: .restricted, isSelected: false, title: VectorL10n.createRoomTypeRestricted, detail: VectorL10n.roomAccessSettingsScreenRestrictedMessage, badgeText: VectorL10n.roomAccessSettingsScreenUpgradeRequired),
|
||||
RoomAccessTypeChooserAccessItem(id: .public, isSelected: false, title: VectorL10n.public, detail: VectorL10n.roomAccessSettingsScreenPublicMessage, badgeText: nil),
|
||||
RoomAccessTypeChooserAccessItem(id: .public, isSelected: false, title: VectorL10n.public, detail: VectorL10n.roomAccessSettingsScreenPublicMessage, badgeText: nil)
|
||||
]
|
||||
|
||||
private(set) var accessItemsSubject: CurrentValueSubject<[RoomAccessTypeChooserAccessItem], Never>
|
||||
@@ -31,9 +30,9 @@ class MockRoomAccessTypeChooserService: RoomAccessTypeChooserServiceProtocol {
|
||||
private(set) var errorSubject: CurrentValueSubject<Error?, Never>
|
||||
|
||||
private(set) var selectedType: RoomAccessTypeChooserAccessType = .private
|
||||
var currentRoomId: String = "!aaabaa:matrix.org"
|
||||
var currentRoomId = "!aaabaa:matrix.org"
|
||||
var versionOverride: String? {
|
||||
return "9"
|
||||
"9"
|
||||
}
|
||||
|
||||
init(accessItems: [RoomAccessTypeChooserAccessItem] = mockAccessItems) {
|
||||
@@ -44,18 +43,14 @@ class MockRoomAccessTypeChooserService: RoomAccessTypeChooserServiceProtocol {
|
||||
}
|
||||
|
||||
func simulateUpdate(accessItems: [RoomAccessTypeChooserAccessItem]) {
|
||||
self.accessItemsSubject.send(accessItems)
|
||||
accessItemsSubject.send(accessItems)
|
||||
}
|
||||
|
||||
func updateSelection(with selectedType: RoomAccessTypeChooserAccessType) {
|
||||
|
||||
}
|
||||
func updateSelection(with selectedType: RoomAccessTypeChooserAccessType) { }
|
||||
|
||||
func updateRoomId(with roomId: String) {
|
||||
currentRoomId = roomId
|
||||
}
|
||||
|
||||
func applySelection(completion: @escaping () -> Void) {
|
||||
|
||||
}
|
||||
func applySelection(completion: @escaping () -> Void) { }
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,8 +14,8 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
protocol RoomAccessTypeChooserServiceProtocol {
|
||||
var accessItemsSubject: CurrentValueSubject<[RoomAccessTypeChooserAccessItem], Never> { get }
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,8 +14,8 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import RiotSwiftUI
|
||||
import XCTest
|
||||
|
||||
class RoomAccessTypeChooserUITests: MockScreenTestCase {
|
||||
// Tests to be implemented.
|
||||
|
||||
+3
-5
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,11 +14,9 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Combine
|
||||
import XCTest
|
||||
|
||||
@testable import RiotSwiftUI
|
||||
|
||||
class RoomAccessTypeChooserViewModelTests: XCTestCase {
|
||||
|
||||
}
|
||||
class RoomAccessTypeChooserViewModelTests: XCTestCase { }
|
||||
|
||||
+2
-4
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct RoomAccessTypeChooser: View {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -55,7 +54,7 @@ struct RoomAccessTypeChooser: View {
|
||||
|
||||
@ViewBuilder
|
||||
private var listContent: some View {
|
||||
ScrollView{
|
||||
ScrollView {
|
||||
VStack(alignment: .leading) {
|
||||
Text(VectorL10n.roomAccessSettingsScreenTitle)
|
||||
.foregroundColor(theme.colors.primaryContent)
|
||||
@@ -84,7 +83,6 @@ struct RoomAccessTypeChooser: View {
|
||||
// MARK: - Previews
|
||||
|
||||
struct RoomAccessTypeChooser_Previews: PreviewProvider {
|
||||
|
||||
static let stateRenderer = MockRoomAccessTypeChooserScreenState.stateRenderer
|
||||
static var previews: some View {
|
||||
stateRenderer.screenGroup(addNavigation: true)
|
||||
|
||||
-1
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct RoomAccessTypeChooserRow: View {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
|
||||
+2
-3
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
class RoomRestrictedAccessSpaceChooserViewProvider: MatrixItemChooserCoordinatorViewProvider {
|
||||
|
||||
private let navTitle: String?
|
||||
|
||||
init(navTitle: String?) {
|
||||
@@ -25,6 +24,6 @@ class RoomRestrictedAccessSpaceChooserViewProvider: MatrixItemChooserCoordinator
|
||||
}
|
||||
|
||||
func view(with viewModel: MatrixItemChooserViewModelType.Context) -> AnyView {
|
||||
return AnyView(RoomRestrictedAccessSpaceChooserSelector(viewModel: viewModel, navTitle: navTitle))
|
||||
AnyView(RoomRestrictedAccessSpaceChooserSelector(viewModel: viewModel, navTitle: navTitle))
|
||||
}
|
||||
}
|
||||
|
||||
+4
-5
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import Foundation
|
||||
|
||||
class RoomRestrictedAccessSpaceChooserItemsProcessor: MatrixItemChooserProcessorProtocol {
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let roomId: String
|
||||
@@ -28,7 +27,7 @@ class RoomRestrictedAccessSpaceChooserItemsProcessor: MatrixItemChooserProcessor
|
||||
init(roomId: String, session: MXSession) {
|
||||
self.roomId = roomId
|
||||
self.session = session
|
||||
self.dataSource = MatrixItemChooserRoomRestrictedAllowedParentsDataSource(roomId: roomId)
|
||||
dataSource = MatrixItemChooserRoomRestrictedAllowedParentsDataSource(roomId: roomId)
|
||||
}
|
||||
|
||||
// MARK: MatrixItemChooserSelectionProcessorProtocol
|
||||
@@ -50,7 +49,7 @@ class RoomRestrictedAccessSpaceChooserItemsProcessor: MatrixItemChooserProcessor
|
||||
}
|
||||
}
|
||||
|
||||
func isItemIncluded(_ item: (MatrixListItemData)) -> Bool {
|
||||
return true
|
||||
func isItemIncluded(_ item: MatrixListItemData) -> Bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct RoomRestrictedAccessSpaceChooserSelector: View {
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
@ObservedObject var viewModel: MatrixItemChooserViewModel.Context
|
||||
@@ -51,5 +50,4 @@ struct RoomRestrictedAccessSpaceChooserSelector: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
-13
@@ -24,7 +24,6 @@ enum RoomSuggestionCoordinatorCoordinatorAction {
|
||||
|
||||
@objcMembers
|
||||
final class RoomSuggestionCoordinator: Coordinator {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -32,7 +31,7 @@ final class RoomSuggestionCoordinator: Coordinator {
|
||||
private let parameters: RoomSuggestionCoordinatorParameters
|
||||
|
||||
private var navigationRouter: NavigationRouterType {
|
||||
return self.parameters.navigationRouter
|
||||
parameters.navigationRouter
|
||||
}
|
||||
|
||||
// MARK: Public
|
||||
@@ -46,31 +45,30 @@ final class RoomSuggestionCoordinator: Coordinator {
|
||||
|
||||
init(parameters: RoomSuggestionCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
|
||||
func start() {
|
||||
MXLog.debug("[RoomSuggestionCoordinator] did start.")
|
||||
let rootCoordinator = self.createRoomSuggestionSpaceChooser()
|
||||
let rootCoordinator = createRoomSuggestionSpaceChooser()
|
||||
rootCoordinator.start()
|
||||
|
||||
self.add(childCoordinator: rootCoordinator)
|
||||
add(childCoordinator: rootCoordinator)
|
||||
|
||||
if self.navigationRouter.modules.isEmpty == false {
|
||||
self.navigationRouter.push(rootCoordinator, animated: true, popCompletion: { [weak self] in
|
||||
if navigationRouter.modules.isEmpty == false {
|
||||
navigationRouter.push(rootCoordinator, animated: true, popCompletion: { [weak self] in
|
||||
self?.remove(childCoordinator: rootCoordinator)
|
||||
})
|
||||
} else {
|
||||
self.navigationRouter.setRootModule(rootCoordinator) { [weak self] in
|
||||
navigationRouter.setRootModule(rootCoordinator) { [weak self] in
|
||||
self?.remove(childCoordinator: rootCoordinator)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func toPresentable() -> UIViewController {
|
||||
return self.navigationRouter.toPresentable()
|
||||
navigationRouter.toPresentable()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
@@ -78,7 +76,7 @@ final class RoomSuggestionCoordinator: Coordinator {
|
||||
func pushScreen(with coordinator: Coordinator & Presentable) {
|
||||
add(childCoordinator: coordinator)
|
||||
|
||||
self.navigationRouter.push(coordinator, animated: true, popCompletion: { [weak self] in
|
||||
navigationRouter.push(coordinator, animated: true, popCompletion: { [weak self] in
|
||||
self?.remove(childCoordinator: coordinator)
|
||||
})
|
||||
|
||||
@@ -91,7 +89,8 @@ final class RoomSuggestionCoordinator: Coordinator {
|
||||
title: VectorL10n.roomSuggestionSettingsScreenTitle,
|
||||
detail: VectorL10n.roomSuggestionSettingsScreenMessage,
|
||||
viewProvider: RoomSuggestionSpaceChooserViewProvider(navTitle: VectorL10n.roomAccessSettingsScreenNavTitle),
|
||||
itemsProcessor: RoomSuggestionSpaceChooserItemsProcessor(roomId: parameters.room.roomId, session: parameters.room.mxSession))
|
||||
itemsProcessor: RoomSuggestionSpaceChooserItemsProcessor(roomId: parameters.room.roomId, session: parameters.room.mxSession)
|
||||
)
|
||||
let coordinator = MatrixItemChooserCoordinator(parameters: paramaters)
|
||||
coordinator.completion = { [weak self] result in
|
||||
guard let self = self else { return }
|
||||
@@ -107,5 +106,4 @@ final class RoomSuggestionCoordinator: Coordinator {
|
||||
}
|
||||
return coordinator
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-5
@@ -26,7 +26,6 @@ import UIKit
|
||||
/// Each bridge should be removed once the underlying Coordinator has been integrated by another Coordinator.
|
||||
@objcMembers
|
||||
final class RoomSuggestionCoordinatorBridgePresenter: NSObject {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -70,7 +69,7 @@ final class RoomSuggestionCoordinatorBridgePresenter: NSObject {
|
||||
}
|
||||
|
||||
func dismiss(animated: Bool, completion: (() -> Void)?) {
|
||||
guard let coordinator = self.coordinator else {
|
||||
guard let coordinator = coordinator else {
|
||||
return
|
||||
}
|
||||
coordinator.toPresentable().dismiss(animated: animated) {
|
||||
@@ -86,9 +85,7 @@ final class RoomSuggestionCoordinatorBridgePresenter: NSObject {
|
||||
// MARK: - UIAdaptivePresentationControllerDelegate
|
||||
|
||||
extension RoomSuggestionCoordinatorBridgePresenter: UIAdaptivePresentationControllerDelegate {
|
||||
|
||||
func roomNotificationSettingsCoordinatorDidComplete(_ presentationController: UIPresentationController) {
|
||||
self.delegate?.roomSuggestionCoordinatorBridgePresenterDelegateDidCancel(self)
|
||||
delegate?.roomSuggestionCoordinatorBridgePresenterDelegateDidCancel(self)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-1
@@ -18,7 +18,6 @@ import Foundation
|
||||
|
||||
/// RoomSuggestionCoordinator input parameters
|
||||
struct RoomSuggestionCoordinatorParameters {
|
||||
|
||||
/// The Matrix room
|
||||
let room: MXRoom
|
||||
|
||||
|
||||
+2
-3
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
class RoomSuggestionSpaceChooserViewProvider: MatrixItemChooserCoordinatorViewProvider {
|
||||
|
||||
private let navTitle: String?
|
||||
|
||||
init(navTitle: String?) {
|
||||
@@ -25,6 +24,6 @@ class RoomSuggestionSpaceChooserViewProvider: MatrixItemChooserCoordinatorViewPr
|
||||
}
|
||||
|
||||
func view(with viewModel: MatrixItemChooserViewModelType.Context) -> AnyView {
|
||||
return AnyView(RoomSuggestionSpaceChooserSelector(viewModel: viewModel, navTitle: navTitle))
|
||||
AnyView(RoomSuggestionSpaceChooserSelector(viewModel: viewModel, navTitle: navTitle))
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -22,7 +22,6 @@ public enum RoomSuggestionSpaceChooserItemsProcessorError: Int, Error {
|
||||
}
|
||||
|
||||
class RoomSuggestionSpaceChooserItemsProcessor: MatrixItemChooserProcessorProtocol {
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let roomId: String
|
||||
@@ -35,7 +34,7 @@ class RoomSuggestionSpaceChooserItemsProcessor: MatrixItemChooserProcessorProtoc
|
||||
init(roomId: String, session: MXSession) {
|
||||
self.roomId = roomId
|
||||
self.session = session
|
||||
self.dataSource = MatrixItemChooserRoomDirectParentsDataSource(roomId: roomId, preselectionMode: .suggestedRoom)
|
||||
dataSource = MatrixItemChooserRoomDirectParentsDataSource(roomId: roomId, preselectionMode: .suggestedRoom)
|
||||
}
|
||||
|
||||
deinit {
|
||||
@@ -43,6 +42,7 @@ class RoomSuggestionSpaceChooserItemsProcessor: MatrixItemChooserProcessorProtoc
|
||||
NotificationCenter.default.removeObserver(observer)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: MatrixItemChooserSelectionProcessorProtocol
|
||||
|
||||
private(set) var dataSource: MatrixItemChooserDataSource
|
||||
@@ -53,11 +53,11 @@ class RoomSuggestionSpaceChooserItemsProcessor: MatrixItemChooserProcessorProtoc
|
||||
let unselectedItems: [String]
|
||||
let selectedItems: [String]
|
||||
if let preselectedItems = dataSource.preselectedItemIds {
|
||||
unselectedItems = preselectedItems.compactMap({ itemId in
|
||||
return !itemsIds.contains(itemId) ? itemId : nil
|
||||
})
|
||||
unselectedItems = preselectedItems.compactMap { itemId in
|
||||
!itemsIds.contains(itemId) ? itemId : nil
|
||||
}
|
||||
selectedItems = itemsIds.compactMap { itemId in
|
||||
return !preselectedItems.contains(itemId) ? itemId : nil
|
||||
!preselectedItems.contains(itemId) ? itemId : nil
|
||||
}
|
||||
} else {
|
||||
unselectedItems = []
|
||||
@@ -78,7 +78,7 @@ class RoomSuggestionSpaceChooserItemsProcessor: MatrixItemChooserProcessorProtoc
|
||||
if let firstError = self.computationErrorList.first {
|
||||
completion(.failure(firstError))
|
||||
} else {
|
||||
self.didBuildSpaceGraphObserver = NotificationCenter.default.addObserver(forName: MXSpaceService.didBuildSpaceGraph, object: nil, queue: OperationQueue.main) { [weak self] notification in
|
||||
self.didBuildSpaceGraphObserver = NotificationCenter.default.addObserver(forName: MXSpaceService.didBuildSpaceGraph, object: nil, queue: OperationQueue.main) { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
|
||||
if let observer = self.didBuildSpaceGraphObserver {
|
||||
@@ -93,8 +93,8 @@ class RoomSuggestionSpaceChooserItemsProcessor: MatrixItemChooserProcessorProtoc
|
||||
}
|
||||
}
|
||||
|
||||
func isItemIncluded(_ item: (MatrixListItemData)) -> Bool {
|
||||
return true
|
||||
func isItemIncluded(_ item: MatrixListItemData) -> Bool {
|
||||
true
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
+1
-3
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct RoomSuggestionSpaceChooserSelector: View {
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
@ObservedObject var viewModel: MatrixItemChooserViewModel.Context
|
||||
@@ -48,5 +47,4 @@ struct RoomSuggestionSpaceChooserSelector: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import MatrixSDK
|
||||
import SwiftUI
|
||||
|
||||
struct RoomUpgradeCoordinatorParameters {
|
||||
let session: MXSession
|
||||
@@ -25,7 +25,6 @@ struct RoomUpgradeCoordinatorParameters {
|
||||
}
|
||||
|
||||
final class RoomUpgradeCoordinator: Coordinator, Presentable {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -53,6 +52,7 @@ final class RoomUpgradeCoordinator: Coordinator, Presentable {
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
func start() {
|
||||
MXLog.debug("[RoomUpgradeCoordinator] did start.")
|
||||
roomUpgradeViewModel.completion = { [weak self] result in
|
||||
@@ -68,6 +68,6 @@ final class RoomUpgradeCoordinator: Coordinator, Presentable {
|
||||
}
|
||||
|
||||
func toPresentable() -> UIViewController {
|
||||
return self.roomUpgradeHostingController
|
||||
roomUpgradeHostingController
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -36,7 +36,7 @@ enum MockRoomUpgradeScreenState: MockScreenState, CaseIterable {
|
||||
}
|
||||
|
||||
/// Generate the view struct for the screen state.
|
||||
var screenView: ([Any], AnyView) {
|
||||
var screenView: ([Any], AnyView) {
|
||||
let service: MockRoomUpgradeService
|
||||
switch self {
|
||||
case .initial:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
@@ -14,14 +14,13 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
typealias RoomUpgradeViewModelType = StateStoreViewModel<RoomUpgradeViewState,
|
||||
Never,
|
||||
RoomUpgradeViewAction>
|
||||
Never,
|
||||
RoomUpgradeViewAction>
|
||||
class RoomUpgradeViewModel: RoomUpgradeViewModelType, RoomUpgradeViewModelProtocol {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -35,7 +34,7 @@ class RoomUpgradeViewModel: RoomUpgradeViewModelType, RoomUpgradeViewModelProtoc
|
||||
// MARK: - Setup
|
||||
|
||||
static func makeRoomUpgradeViewModel(roomUpgradeService: RoomUpgradeServiceProtocol) -> RoomUpgradeViewModelProtocol {
|
||||
return RoomUpgradeViewModel(roomUpgradeService: roomUpgradeService)
|
||||
RoomUpgradeViewModel(roomUpgradeService: roomUpgradeService)
|
||||
}
|
||||
|
||||
private init(roomUpgradeService: RoomUpgradeServiceProtocol) {
|
||||
@@ -45,7 +44,7 @@ class RoomUpgradeViewModel: RoomUpgradeViewModelType, RoomUpgradeViewModelProtoc
|
||||
}
|
||||
|
||||
private static func defaultState(roomUpgradeService: RoomUpgradeServiceProtocol) -> RoomUpgradeViewState {
|
||||
return RoomUpgradeViewState(waitingMessage: nil, isLoading: false, parentSpaceName: roomUpgradeService.parentSpaceName)
|
||||
RoomUpgradeViewState(waitingMessage: nil, isLoading: false, parentSpaceName: roomUpgradeService.parentSpaceName)
|
||||
}
|
||||
|
||||
private func setupObservers() {
|
||||
@@ -53,7 +52,7 @@ class RoomUpgradeViewModel: RoomUpgradeViewModelType, RoomUpgradeViewModelProtoc
|
||||
.upgradingSubject
|
||||
.sink { [weak self] isUpgrading in
|
||||
self?.state.isLoading = isUpgrading
|
||||
self?.state.waitingMessage = isUpgrading ? VectorL10n.roomAccessSettingsScreenUpgradeAlertUpgrading: nil
|
||||
self?.state.waitingMessage = isUpgrading ? VectorL10n.roomAccessSettingsScreenUpgradeAlertUpgrading : nil
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
@@ -65,7 +64,7 @@ class RoomUpgradeViewModel: RoomUpgradeViewModelType, RoomUpgradeViewModelProtoc
|
||||
case .cancel:
|
||||
completion?(.cancel(roomUpgradeService.currentRoomId))
|
||||
case .done(let autoInviteUsers):
|
||||
roomUpgradeService.upgradeRoom(autoInviteUsers: autoInviteUsers) { [weak self] success, roomId in
|
||||
roomUpgradeService.upgradeRoom(autoInviteUsers: autoInviteUsers) { [weak self] success, _ in
|
||||
guard let self = self else { return }
|
||||
if success {
|
||||
self.completion?(.done(self.roomUpgradeService.currentRoomId))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import Foundation
|
||||
|
||||
protocol RoomUpgradeViewModelProtocol {
|
||||
|
||||
var completion: ((RoomUpgradeViewModelResult) -> Void)? { get set }
|
||||
static func makeRoomUpgradeViewModel(roomUpgradeService: RoomUpgradeServiceProtocol) -> RoomUpgradeViewModelProtocol
|
||||
var context: RoomUpgradeViewModelType.Context { get }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,12 +14,11 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Foundation
|
||||
import MatrixSDK
|
||||
|
||||
class RoomUpgradeService: RoomUpgradeServiceProtocol {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -37,7 +36,7 @@ class RoomUpgradeService: RoomUpgradeServiceProtocol {
|
||||
private(set) var currentRoomId: String
|
||||
|
||||
var parentSpaceName: String? {
|
||||
guard let parentId = self.parentSpaceId else {
|
||||
guard let parentId = parentSpaceId else {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -53,11 +52,11 @@ class RoomUpgradeService: RoomUpgradeServiceProtocol {
|
||||
|
||||
init(session: MXSession, roomId: String, parentSpaceId: String?, versionOverride: String) {
|
||||
self.session = session
|
||||
self.currentRoomId = roomId
|
||||
currentRoomId = roomId
|
||||
self.parentSpaceId = parentSpaceId
|
||||
self.versionOverride = versionOverride
|
||||
self.upgradingSubject = CurrentValueSubject(false)
|
||||
self.errorSubject = CurrentValueSubject(nil)
|
||||
upgradingSubject = CurrentValueSubject(false)
|
||||
errorSubject = CurrentValueSubject(nil)
|
||||
}
|
||||
|
||||
deinit {
|
||||
@@ -70,18 +69,18 @@ class RoomUpgradeService: RoomUpgradeServiceProtocol {
|
||||
func upgradeRoom(autoInviteUsers: Bool, completion: @escaping (Bool, String) -> Void) {
|
||||
upgradingSubject.send(true)
|
||||
|
||||
if autoInviteUsers, let room = session.room(withRoomId: self.currentRoomId) {
|
||||
self.currentOperation = room.members { [weak self] response in
|
||||
if autoInviteUsers, let room = session.room(withRoomId: currentRoomId) {
|
||||
currentOperation = room.members { [weak self] response in
|
||||
guard let self = self else { return }
|
||||
switch response {
|
||||
case .success(let members):
|
||||
let memberIds: [String] = members?.members.compactMap({ member in
|
||||
let memberIds: [String] = members?.members.compactMap { member in
|
||||
guard member.membership == .join, member.userId != self.session.myUserId else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return member.userId
|
||||
}) ?? []
|
||||
} ?? []
|
||||
self.upgradeRoom(to: self.versionOverride, inviteUsers: memberIds, completion: completion)
|
||||
case .failure(let error):
|
||||
self.upgradingSubject.send(false)
|
||||
@@ -89,7 +88,7 @@ class RoomUpgradeService: RoomUpgradeServiceProtocol {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.upgradeRoom(to: versionOverride, inviteUsers: [], completion: completion)
|
||||
upgradeRoom(to: versionOverride, inviteUsers: [], completion: completion)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +97,7 @@ class RoomUpgradeService: RoomUpgradeServiceProtocol {
|
||||
private func upgradeRoom(to versionOverride: String, inviteUsers userIds: [String], completion: @escaping (Bool, String) -> Void) {
|
||||
// Need to disable graph update during this process as a lot of syncs will occure
|
||||
session.spaceService.graphUpdateEnabled = false
|
||||
currentOperation = session.matrixRestClient.upgradeRoom(withId: self.currentRoomId, to: versionOverride) { [weak self] response in
|
||||
currentOperation = session.matrixRestClient.upgradeRoom(withId: currentRoomId, to: versionOverride) { [weak self] response in
|
||||
guard let self = self else { return }
|
||||
|
||||
switch response {
|
||||
@@ -108,7 +107,7 @@ class RoomUpgradeService: RoomUpgradeServiceProtocol {
|
||||
let parentSpaces = self.session.spaceService.directParentIds(ofRoomWithId: oldRoomId)
|
||||
self.moveRoom(from: oldRoomId, to: replacementRoomId, within: Array(parentSpaces), at: 0) {
|
||||
self.session.spaceService.graphUpdateEnabled = true
|
||||
self.didBuildSpaceGraphObserver = NotificationCenter.default.addObserver(forName: MXSpaceService.didBuildSpaceGraph, object: nil, queue: OperationQueue.main) { [weak self] notification in
|
||||
self.didBuildSpaceGraphObserver = NotificationCenter.default.addObserver(forName: MXSpaceService.didBuildSpaceGraph, object: nil, queue: OperationQueue.main) { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
|
||||
if let observer = self.didBuildSpaceGraphObserver {
|
||||
@@ -144,7 +143,7 @@ class RoomUpgradeService: RoomUpgradeServiceProtocol {
|
||||
}
|
||||
|
||||
space.moveChild(withRoomId: roomId, to: newRoomId) { [weak self] response in
|
||||
guard let self = self else { return }
|
||||
guard let self = self else { return }
|
||||
|
||||
if let error = response.error {
|
||||
MXLog.warning("[RoomUpgradeService] moveRoom \(roomId) to \(newRoomId) within \(space.spaceId): failed due to error: \(error)")
|
||||
@@ -158,13 +157,13 @@ class RoomUpgradeService: RoomUpgradeServiceProtocol {
|
||||
/// Recurse to the next index once done.
|
||||
private func inviteUser(from userIds: [String], at index: Int, completion: @escaping (Bool, String) -> Void) {
|
||||
guard index < userIds.count else {
|
||||
self.upgradingSubject.send(false)
|
||||
upgradingSubject.send(false)
|
||||
completion(true, currentRoomId)
|
||||
return
|
||||
}
|
||||
|
||||
currentOperation = session.matrixRestClient.invite(.userId(userIds[index]), toRoom: currentRoomId) { [weak self] response in
|
||||
guard let self = self else { return }
|
||||
guard let self = self else { return }
|
||||
|
||||
self.currentOperation = nil
|
||||
if let error = response.error {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,24 +14,22 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
class MockRoomUpgradeService: RoomUpgradeServiceProtocol {
|
||||
var currentRoomId: String = "!sfdlksjdflkfjds:matrix.org"
|
||||
var currentRoomId = "!sfdlksjdflkfjds:matrix.org"
|
||||
|
||||
var errorSubject: CurrentValueSubject<Error?, Never>
|
||||
var upgradingSubject: CurrentValueSubject<Bool, Never>
|
||||
var parentSpaceName: String? {
|
||||
return "Parent space name"
|
||||
"Parent space name"
|
||||
}
|
||||
|
||||
init() {
|
||||
self.errorSubject = CurrentValueSubject(nil)
|
||||
self.upgradingSubject = CurrentValueSubject(false)
|
||||
errorSubject = CurrentValueSubject(nil)
|
||||
upgradingSubject = CurrentValueSubject(false)
|
||||
}
|
||||
|
||||
func upgradeRoom(autoInviteUsers: Bool, completion: @escaping (Bool, String) -> Void) {
|
||||
|
||||
}
|
||||
func upgradeRoom(autoInviteUsers: Bool, completion: @escaping (Bool, String) -> Void) { }
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,8 +14,8 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
protocol RoomUpgradeServiceProtocol {
|
||||
var currentRoomId: String { get }
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import RiotSwiftUI
|
||||
import XCTest
|
||||
|
||||
class RoomUpgradeUITests: MockScreenTestCase {
|
||||
// Tests to be implemented.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,8 +14,8 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Combine
|
||||
import XCTest
|
||||
|
||||
@testable import RiotSwiftUI
|
||||
|
||||
@@ -24,7 +24,5 @@ class RoomUpgradeViewModelTests: XCTestCase {
|
||||
var viewModel: RoomUpgradeViewModelProtocol!
|
||||
var context: RoomUpgradeViewModelType.Context!
|
||||
|
||||
override func setUpWithError() throws {
|
||||
}
|
||||
|
||||
override func setUpWithError() throws { }
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,10 +17,9 @@
|
||||
import SwiftUI
|
||||
|
||||
struct RoomUpgrade: View {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
@State var autoInviteUsers: Bool = true
|
||||
@State var autoInviteUsers = true
|
||||
|
||||
// MARK: Private
|
||||
|
||||
@@ -86,13 +85,13 @@ struct RoomUpgrade: View {
|
||||
.padding(.horizontal, 24)
|
||||
.padding(.vertical, 16)
|
||||
}
|
||||
.background(RoundedRectangle.init(cornerRadius: 8).foregroundColor(theme.colors.background))
|
||||
.background(RoundedRectangle(cornerRadius: 8).foregroundColor(theme.colors.background))
|
||||
.padding(.horizontal, 20)
|
||||
.frame(minWidth: 0, maxWidth: 500)
|
||||
}
|
||||
|
||||
private func noteText(_ message: String) -> some View {
|
||||
return Text(message)
|
||||
Text(message)
|
||||
.multilineTextAlignment(.center)
|
||||
.font(theme.fonts.subheadline)
|
||||
.foregroundColor(theme.colors.secondaryContent)
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import MatrixSDK
|
||||
import Combine
|
||||
import MatrixSDK
|
||||
import SwiftUI
|
||||
|
||||
struct TimelinePollCoordinatorParameters {
|
||||
let session: MXSession
|
||||
@@ -25,7 +25,6 @@ struct TimelinePollCoordinatorParameters {
|
||||
}
|
||||
|
||||
final class TimelinePollCoordinator: Coordinator, Presentable, PollAggregatorDelegate {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -81,25 +80,24 @@ final class TimelinePollCoordinator: Coordinator, Presentable, PollAggregatorDel
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
func start() {
|
||||
|
||||
}
|
||||
|
||||
func start() { }
|
||||
|
||||
func toPresentable() -> UIViewController {
|
||||
return VectorHostingController(rootView: TimelinePollView(viewModel: viewModel.context),
|
||||
forceZeroSafeAreaInsets: true)
|
||||
VectorHostingController(rootView: TimelinePollView(viewModel: viewModel.context),
|
||||
forceZeroSafeAreaInsets: true)
|
||||
}
|
||||
|
||||
func canEndPoll() -> Bool {
|
||||
return pollAggregator.poll.isClosed == false
|
||||
pollAggregator.poll.isClosed == false
|
||||
}
|
||||
|
||||
func canEditPoll() -> Bool {
|
||||
return pollAggregator.poll.isClosed == false && pollAggregator.poll.totalAnswerCount == 0
|
||||
pollAggregator.poll.isClosed == false && pollAggregator.poll.totalAnswerCount == 0
|
||||
}
|
||||
|
||||
func endPoll() {
|
||||
parameters.room.sendPollEnd(for: parameters.pollStartEvent, threadId: nil, localEcho: nil, success: nil) { [weak self] error in
|
||||
parameters.room.sendPollEnd(for: parameters.pollStartEvent, threadId: nil, localEcho: nil, success: nil) { [weak self] _ in
|
||||
self?.viewModel.showClosingFailure()
|
||||
}
|
||||
}
|
||||
@@ -110,17 +108,11 @@ final class TimelinePollCoordinator: Coordinator, Presentable, PollAggregatorDel
|
||||
viewModel.updateWithPollDetails(buildTimelinePollFrom(aggregator.poll))
|
||||
}
|
||||
|
||||
func pollAggregatorDidStartLoading(_ aggregator: PollAggregator) {
|
||||
|
||||
}
|
||||
func pollAggregatorDidStartLoading(_ aggregator: PollAggregator) { }
|
||||
|
||||
func pollAggregatorDidEndLoading(_ aggregator: PollAggregator) {
|
||||
|
||||
}
|
||||
func pollAggregatorDidEndLoading(_ aggregator: PollAggregator) { }
|
||||
|
||||
func pollAggregator(_ aggregator: PollAggregator, didFailWithError: Error) {
|
||||
|
||||
}
|
||||
func pollAggregator(_ aggregator: PollAggregator, didFailWithError: Error) { }
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
@@ -129,19 +121,19 @@ final class TimelinePollCoordinator: Coordinator, Presentable, PollAggregatorDel
|
||||
func buildTimelinePollFrom(_ poll: PollProtocol) -> TimelinePollDetails {
|
||||
let answerOptions = poll.answerOptions.map { pollAnswerOption in
|
||||
TimelinePollAnswerOption(id: pollAnswerOption.id,
|
||||
text: pollAnswerOption.text,
|
||||
count: pollAnswerOption.count,
|
||||
winner: pollAnswerOption.isWinner,
|
||||
selected: pollAnswerOption.isCurrentUserSelection)
|
||||
text: pollAnswerOption.text,
|
||||
count: pollAnswerOption.count,
|
||||
winner: pollAnswerOption.isWinner,
|
||||
selected: pollAnswerOption.isCurrentUserSelection)
|
||||
}
|
||||
|
||||
return TimelinePollDetails(question: poll.text,
|
||||
answerOptions: answerOptions,
|
||||
closed: poll.isClosed,
|
||||
totalAnswerCount: poll.totalAnswerCount,
|
||||
type: pollKindToTimelinePollType(poll.kind),
|
||||
maxAllowedSelections: poll.maxAllowedSelections,
|
||||
hasBeenEdited: poll.hasBeenEdited)
|
||||
answerOptions: answerOptions,
|
||||
closed: poll.isClosed,
|
||||
totalAnswerCount: poll.totalAnswerCount,
|
||||
type: pollKindToTimelinePollType(poll.kind),
|
||||
maxAllowedSelections: poll.maxAllowedSelections,
|
||||
hasBeenEdited: poll.hasBeenEdited)
|
||||
}
|
||||
|
||||
private func pollKindToTimelinePollType(_ kind: PollKind) -> TimelinePollType {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -22,9 +22,7 @@ class TimelinePollProvider {
|
||||
var session: MXSession?
|
||||
var coordinatorsForEventIdentifiers = [String: TimelinePollCoordinator]()
|
||||
|
||||
private init() {
|
||||
|
||||
}
|
||||
private init() { }
|
||||
|
||||
/// Create or retrieve the poll timeline coordinator for this event and return
|
||||
/// a view to be displayed in the timeline
|
||||
@@ -49,6 +47,6 @@ class TimelinePollProvider {
|
||||
|
||||
/// Retrieve the poll timeline coordinator for the given event or nil if it hasn't been created yet
|
||||
func timelinePollCoordinatorForEventIdentifier(_ eventIdentifier: String) -> TimelinePollCoordinator? {
|
||||
return coordinatorsForEventIdentifiers[eventIdentifier]
|
||||
coordinatorsForEventIdentifiers[eventIdentifier]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import RiotSwiftUI
|
||||
import XCTest
|
||||
|
||||
class TimelinePollUITests: MockScreenTestCase {
|
||||
func testOpenDisclosedPoll() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,8 +14,8 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Combine
|
||||
import XCTest
|
||||
|
||||
@testable import RiotSwiftUI
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,7 @@
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
typealias TimelinePollViewModelCallback = ((TimelinePollViewModelResult) -> Void)
|
||||
typealias TimelinePollViewModelCallback = (TimelinePollViewModelResult) -> Void
|
||||
|
||||
enum TimelinePollViewAction {
|
||||
case selectAnswerOptionWithIdentifier(String)
|
||||
@@ -63,7 +63,7 @@ struct TimelinePollDetails {
|
||||
var totalAnswerCount: UInt
|
||||
var type: TimelinePollType
|
||||
var maxAllowedSelections: UInt
|
||||
var hasBeenEdited: Bool = true
|
||||
var hasBeenEdited = true
|
||||
|
||||
init(question: String, answerOptions: [TimelinePollAnswerOption],
|
||||
closed: Bool,
|
||||
@@ -81,7 +81,7 @@ struct TimelinePollDetails {
|
||||
}
|
||||
|
||||
var hasCurrentUserVoted: Bool {
|
||||
answerOptions.filter { $0.selected == true}.count > 0
|
||||
answerOptions.filter { $0.selected == true }.count > 0
|
||||
}
|
||||
|
||||
var shouldDiscloseResults: Bool {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -27,16 +27,16 @@ enum MockTimelinePollScreenState: MockScreenState, CaseIterable {
|
||||
TimelinePollDetails.self
|
||||
}
|
||||
|
||||
var screenView: ([Any], AnyView) {
|
||||
var screenView: ([Any], AnyView) {
|
||||
let answerOptions = [TimelinePollAnswerOption(id: "1", text: "First", count: 10, winner: false, selected: false),
|
||||
TimelinePollAnswerOption(id: "2", text: "Second", count: 5, winner: false, selected: true),
|
||||
TimelinePollAnswerOption(id: "3", text: "Third", count: 15, winner: true, selected: false)]
|
||||
|
||||
let poll = TimelinePollDetails(question: "Question",
|
||||
answerOptions: answerOptions,
|
||||
closed: (self == .closedDisclosed || self == .closedUndisclosed ? true : false),
|
||||
closed: self == .closedDisclosed || self == .closedUndisclosed ? true : false,
|
||||
totalAnswerCount: 20,
|
||||
type: (self == .closedDisclosed || self == .openDisclosed ? .disclosed : .undisclosed),
|
||||
type: self == .closedDisclosed || self == .openDisclosed ? .disclosed : .undisclosed,
|
||||
maxAllowedSelections: 1,
|
||||
hasBeenEdited: false)
|
||||
|
||||
|
||||
@@ -14,14 +14,13 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
typealias TimelinePollViewModelType = StateStoreViewModel<TimelinePollViewState,
|
||||
Never,
|
||||
TimelinePollViewAction>
|
||||
Never,
|
||||
TimelinePollViewAction>
|
||||
class TimelinePollViewModel: TimelinePollViewModelType, TimelinePollViewModelProtocol {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -40,14 +39,13 @@ class TimelinePollViewModel: TimelinePollViewModelType, TimelinePollViewModelPro
|
||||
|
||||
override func process(viewAction: TimelinePollViewAction) {
|
||||
switch viewAction {
|
||||
|
||||
// Update local state. An update will be pushed from the coordinator once sent.
|
||||
case .selectAnswerOptionWithIdentifier(let identifier):
|
||||
guard !state.poll.closed else {
|
||||
return
|
||||
}
|
||||
|
||||
if (state.poll.maxAllowedSelections == 1) {
|
||||
if state.poll.maxAllowedSelections == 1 {
|
||||
updateSingleSelectPollLocalState(selectedAnswerIdentifier: identifier, callback: completion)
|
||||
} else {
|
||||
updateMultiSelectPollLocalState(&state, selectedAnswerIdentifier: identifier, callback: completion)
|
||||
@@ -98,12 +96,12 @@ class TimelinePollViewModel: TimelinePollViewModelType, TimelinePollViewModelPro
|
||||
|
||||
let isDeselecting = selectedAnswerOptions.filter { $0.id == selectedAnswerIdentifier }.count > 0
|
||||
|
||||
if !isDeselecting && selectedAnswerOptions.count >= state.poll.maxAllowedSelections {
|
||||
if !isDeselecting, selectedAnswerOptions.count >= state.poll.maxAllowedSelections {
|
||||
return
|
||||
}
|
||||
|
||||
state.poll.answerOptions.updateEach { answerOption in
|
||||
if (answerOption.id != selectedAnswerIdentifier) {
|
||||
if answerOption.id != selectedAnswerIdentifier {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct TimelinePollAnswerOptionButton: View {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -47,7 +46,6 @@ struct TimelinePollAnswerOptionButton: View {
|
||||
var answerOptionLabel: some View {
|
||||
VStack(alignment: .leading, spacing: 12.0) {
|
||||
HStack(alignment: .top, spacing: 8.0) {
|
||||
|
||||
if !poll.closed {
|
||||
Image(uiImage: answerOption.selected ? Asset.Images.pollCheckboxSelected.image : Asset.Images.pollCheckboxDefault.image)
|
||||
}
|
||||
@@ -56,7 +54,7 @@ struct TimelinePollAnswerOptionButton: View {
|
||||
.font(theme.fonts.body)
|
||||
.foregroundColor(theme.colors.primaryContent)
|
||||
|
||||
if poll.closed && answerOption.winner {
|
||||
if poll.closed, answerOption.winner {
|
||||
Spacer()
|
||||
Image(uiImage: Asset.Images.pollWinnerIcon.image)
|
||||
}
|
||||
@@ -69,7 +67,7 @@ struct TimelinePollAnswerOptionButton: View {
|
||||
.progressViewStyle(LinearProgressViewStyle())
|
||||
.scaleEffect(x: 1.0, y: 1.2, anchor: .center)
|
||||
|
||||
if (poll.shouldDiscloseResults) {
|
||||
if poll.shouldDiscloseResults {
|
||||
Text(answerOption.count == 1 ? VectorL10n.pollTimelineOneVote : VectorL10n.pollTimelineVotesCount(Int(answerOption.count)))
|
||||
.font(theme.fonts.footnote)
|
||||
.foregroundColor(poll.closed && answerOption.winner ? theme.colors.accent : theme.colors.secondaryContent)
|
||||
@@ -107,33 +105,33 @@ struct TimelinePollAnswerOptionButton_Previews: PreviewProvider {
|
||||
VStack {
|
||||
TimelinePollAnswerOptionButton(poll: buildPoll(closed: false, type: type),
|
||||
answerOption: buildAnswerOption(selected: false),
|
||||
action: {})
|
||||
action: { })
|
||||
|
||||
TimelinePollAnswerOptionButton(poll: buildPoll(closed: false, type: type),
|
||||
answerOption: buildAnswerOption(selected: true),
|
||||
action: {})
|
||||
action: { })
|
||||
|
||||
TimelinePollAnswerOptionButton(poll: buildPoll(closed: true, type: type),
|
||||
answerOption: buildAnswerOption(selected: false, winner: false),
|
||||
action: {})
|
||||
action: { })
|
||||
|
||||
TimelinePollAnswerOptionButton(poll: buildPoll(closed: true, type: type),
|
||||
answerOption: buildAnswerOption(selected: false, winner: true),
|
||||
action: {})
|
||||
action: { })
|
||||
|
||||
TimelinePollAnswerOptionButton(poll: buildPoll(closed: true, type: type),
|
||||
answerOption: buildAnswerOption(selected: true, winner: false),
|
||||
action: {})
|
||||
action: { })
|
||||
|
||||
TimelinePollAnswerOptionButton(poll: buildPoll(closed: true, type: type),
|
||||
answerOption: buildAnswerOption(selected: true, winner: true),
|
||||
action: {})
|
||||
action: { })
|
||||
|
||||
let longText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
|
||||
|
||||
TimelinePollAnswerOptionButton(poll: buildPoll(closed: true, type: type),
|
||||
answerOption: buildAnswerOption(text: longText, selected: true, winner: true),
|
||||
action: {})
|
||||
action: { })
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,12 +139,12 @@ struct TimelinePollAnswerOptionButton_Previews: PreviewProvider {
|
||||
|
||||
static func buildPoll(closed: Bool, type: TimelinePollType) -> TimelinePollDetails {
|
||||
TimelinePollDetails(question: "",
|
||||
answerOptions: [],
|
||||
closed: closed,
|
||||
totalAnswerCount: 100,
|
||||
type: type,
|
||||
maxAllowedSelections: 1,
|
||||
hasBeenEdited: false)
|
||||
answerOptions: [],
|
||||
closed: closed,
|
||||
totalAnswerCount: 100,
|
||||
type: type,
|
||||
maxAllowedSelections: 1,
|
||||
hasBeenEdited: false)
|
||||
}
|
||||
|
||||
static func buildAnswerOption(text: String = "Test", selected: Bool, winner: Bool = false) -> TimelinePollAnswerOption {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct TimelinePollView: View {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -32,7 +31,6 @@ struct TimelinePollView: View {
|
||||
let poll = viewModel.viewState.poll
|
||||
|
||||
VStack(alignment: .leading, spacing: 16.0) {
|
||||
|
||||
Text(poll.question)
|
||||
.font(theme.fonts.bodySB)
|
||||
.foregroundColor(theme.colors.primaryContent) +
|
||||
@@ -77,12 +75,12 @@ struct TimelinePollView: View {
|
||||
return VectorL10n.pollTimelineTotalNoVotes
|
||||
case 1:
|
||||
return (poll.hasCurrentUserVoted || poll.type == .undisclosed ?
|
||||
VectorL10n.pollTimelineTotalOneVote :
|
||||
VectorL10n.pollTimelineTotalOneVoteNotVoted)
|
||||
VectorL10n.pollTimelineTotalOneVote :
|
||||
VectorL10n.pollTimelineTotalOneVoteNotVoted)
|
||||
default:
|
||||
return (poll.hasCurrentUserVoted || poll.type == .undisclosed ?
|
||||
VectorL10n.pollTimelineTotalVotes(Int(poll.totalAnswerCount)) :
|
||||
VectorL10n.pollTimelineTotalVotesNotVoted(Int(poll.totalAnswerCount)))
|
||||
VectorL10n.pollTimelineTotalVotes(Int(poll.totalAnswerCount)) :
|
||||
VectorL10n.pollTimelineTotalVotesNotVoted(Int(poll.totalAnswerCount)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-10
@@ -14,10 +14,10 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
import Combine
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
protocol UserSuggestionCoordinatorDelegate: AnyObject {
|
||||
func userSuggestionCoordinator(_ coordinator: UserSuggestionCoordinator, didRequestMentionForMember member: MXRoomMember, textTrigger: String?)
|
||||
@@ -30,7 +30,6 @@ struct UserSuggestionCoordinatorParameters {
|
||||
}
|
||||
|
||||
final class UserSuggestionCoordinator: Coordinator, Presentable {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -94,12 +93,11 @@ final class UserSuggestionCoordinator: Coordinator, Presentable {
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
func start() {
|
||||
|
||||
}
|
||||
|
||||
func start() { }
|
||||
|
||||
func toPresentable() -> UIViewController {
|
||||
return self.userSuggestionHostingController
|
||||
userSuggestionHostingController
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
@@ -131,13 +129,12 @@ final class UserSuggestionCoordinator: Coordinator, Presentable {
|
||||
}
|
||||
|
||||
private class UserSuggestionCoordinatorRoomMemberProvider: RoomMembersProviderProtocol {
|
||||
|
||||
private let room: MXRoom
|
||||
|
||||
var roomMembers: [MXRoomMember] = []
|
||||
|
||||
init(room: MXRoom) {
|
||||
self.room = room;
|
||||
self.room = room
|
||||
}
|
||||
|
||||
func fetchMembers(_ members: @escaping ([RoomMembersProviderMember]) -> Void) {
|
||||
|
||||
+6
-7
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -24,10 +24,9 @@ protocol UserSuggestionCoordinatorBridgeDelegate: AnyObject {
|
||||
|
||||
@objcMembers
|
||||
final class UserSuggestionCoordinatorBridge: NSObject {
|
||||
|
||||
private var _userSuggestionCoordinator: Any? = nil
|
||||
private var _userSuggestionCoordinator: Any?
|
||||
fileprivate var userSuggestionCoordinator: UserSuggestionCoordinator {
|
||||
return _userSuggestionCoordinator as! UserSuggestionCoordinator
|
||||
_userSuggestionCoordinator as! UserSuggestionCoordinator
|
||||
}
|
||||
|
||||
weak var delegate: UserSuggestionCoordinatorBridgeDelegate?
|
||||
@@ -35,7 +34,7 @@ final class UserSuggestionCoordinatorBridge: NSObject {
|
||||
init(mediaManager: MXMediaManager, room: MXRoom) {
|
||||
let parameters = UserSuggestionCoordinatorParameters(mediaManager: mediaManager, room: room)
|
||||
let userSuggestionCoordinator = UserSuggestionCoordinator(parameters: parameters)
|
||||
self._userSuggestionCoordinator = userSuggestionCoordinator
|
||||
_userSuggestionCoordinator = userSuggestionCoordinator
|
||||
|
||||
super.init()
|
||||
|
||||
@@ -43,11 +42,11 @@ final class UserSuggestionCoordinatorBridge: NSObject {
|
||||
}
|
||||
|
||||
func processTextMessage(_ textMessage: String) {
|
||||
return self.userSuggestionCoordinator.processTextMessage(textMessage)
|
||||
userSuggestionCoordinator.processTextMessage(textMessage)
|
||||
}
|
||||
|
||||
func toPresentable() -> UIViewController? {
|
||||
return self.userSuggestionCoordinator.toPresentable()
|
||||
userSuggestionCoordinator.toPresentable()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,8 +14,8 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
struct RoomMembersProviderMember {
|
||||
var userId: String
|
||||
@@ -34,7 +34,6 @@ struct UserSuggestionServiceItem: UserSuggestionItemProtocol {
|
||||
}
|
||||
|
||||
class UserSuggestionService: UserSuggestionServiceProtocol {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -58,7 +57,7 @@ class UserSuggestionService: UserSuggestionServiceProtocol {
|
||||
init(roomMemberProvider: RoomMembersProviderProtocol, shouldDebounce: Bool = true) {
|
||||
self.roomMemberProvider = roomMemberProvider
|
||||
|
||||
if (shouldDebounce) {
|
||||
if shouldDebounce {
|
||||
currentTextTriggerSubject
|
||||
.debounce(for: 0.5, scheduler: RunLoop.main)
|
||||
.removeDuplicates()
|
||||
@@ -79,12 +78,12 @@ class UserSuggestionService: UserSuggestionServiceProtocol {
|
||||
let lastComponent = textMessage.components(separatedBy: .whitespaces).last,
|
||||
lastComponent.prefix(while: { $0 == "@" }).count == 1 // Partial username should start with one and only one "@" character
|
||||
else {
|
||||
self.items.send([])
|
||||
self.currentTextTriggerSubject.send(nil)
|
||||
items.send([])
|
||||
currentTextTriggerSubject.send(nil)
|
||||
return
|
||||
}
|
||||
|
||||
self.currentTextTriggerSubject.send(lastComponent)
|
||||
currentTextTriggerSubject.send(lastComponent)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
@@ -105,12 +104,12 @@ class UserSuggestionService: UserSuggestionServiceProtocol {
|
||||
UserSuggestionServiceItem(userId: member.userId, displayName: member.displayName, avatarUrl: member.avatarUrl)
|
||||
}
|
||||
|
||||
self.items.send(self.suggestionItems.filter({ userSuggestion in
|
||||
self.items.send(self.suggestionItems.filter { userSuggestion in
|
||||
let containedInUsername = userSuggestion.userId.lowercased().contains(partialName.lowercased())
|
||||
let containedInDisplayName = (userSuggestion.displayName ?? "").lowercased().contains(partialName.lowercased())
|
||||
|
||||
return (containedInUsername || containedInDisplayName)
|
||||
}))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,8 +14,8 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
protocol UserSuggestionItemProtocol: Avatarable {
|
||||
var userId: String { get }
|
||||
@@ -24,7 +24,6 @@ protocol UserSuggestionItemProtocol: Avatarable {
|
||||
}
|
||||
|
||||
protocol UserSuggestionServiceProtocol {
|
||||
|
||||
var items: CurrentValueSubject<[UserSuggestionItemProtocol], Never> { get }
|
||||
|
||||
var currentTextTrigger: String? { get }
|
||||
@@ -38,6 +37,7 @@ extension UserSuggestionItemProtocol {
|
||||
var mxContentUri: String? {
|
||||
avatarUrl
|
||||
}
|
||||
|
||||
var matrixItemId: String {
|
||||
userId
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,8 +14,8 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import RiotSwiftUI
|
||||
import XCTest
|
||||
|
||||
class UserSuggestionUITests: MockScreenTestCase {
|
||||
func testUserSuggestionScreen() throws {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,13 +14,12 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Combine
|
||||
import XCTest
|
||||
|
||||
@testable import RiotSwiftUI
|
||||
|
||||
class UserSuggestionServiceTests: XCTestCase {
|
||||
|
||||
var service: UserSuggestionService?
|
||||
|
||||
override func setUp() {
|
||||
@@ -107,12 +106,11 @@ class UserSuggestionServiceTests: XCTestCase {
|
||||
|
||||
extension UserSuggestionServiceTests: RoomMembersProviderProtocol {
|
||||
func fetchMembers(_ members: @escaping ([RoomMembersProviderMember]) -> Void) {
|
||||
|
||||
let users = [("Alice", "@alice:matrix.org"),
|
||||
("Bob", "@bob:matrix.org")]
|
||||
|
||||
members(users.map({ user in
|
||||
members(users.map { user in
|
||||
RoomMembersProviderMember(userId: user.1, displayName: user.0, avatarUrl: "")
|
||||
}))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -20,13 +20,13 @@ import SwiftUI
|
||||
enum MockUserSuggestionScreenState: MockScreenState, CaseIterable {
|
||||
case multipleResults
|
||||
|
||||
static private var members: [RoomMembersProviderMember]!
|
||||
private static var members: [RoomMembersProviderMember]!
|
||||
|
||||
var screenType: Any.Type {
|
||||
UserSuggestionList.self
|
||||
}
|
||||
|
||||
var screenView: ([Any], AnyView) {
|
||||
var screenView: ([Any], AnyView) {
|
||||
let service = UserSuggestionService(roomMemberProvider: self)
|
||||
let listViewModel = UserSuggestionViewModel(userSuggestionService: service)
|
||||
|
||||
@@ -37,7 +37,7 @@ enum MockUserSuggestionScreenState: MockScreenState, CaseIterable {
|
||||
return (
|
||||
[service, listViewModel],
|
||||
AnyView(UserSuggestionListWithInput(viewModel: viewModel)
|
||||
.addDependency(MockAvatarService.example))
|
||||
.addDependency(MockAvatarService.example))
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ extension MockUserSuggestionScreenState: RoomMembersProviderProtocol {
|
||||
}
|
||||
|
||||
private func generateUsersWithCount(_ count: UInt) -> [RoomMembersProviderMember] {
|
||||
return (0..<count).map { _ in
|
||||
(0..<count).map { _ in
|
||||
let identifier = "@" + UUID().uuidString
|
||||
return RoomMembersProviderMember(userId: identifier, displayName: identifier, avatarUrl: "mxc://matrix.org/VyNYAgahaiAzUoOeZETtQ")
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,15 +14,14 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
typealias UserSuggestionViewModelType = StateStoreViewModel <UserSuggestionViewState,
|
||||
Never,
|
||||
UserSuggestionViewAction>
|
||||
typealias UserSuggestionViewModelType = StateStoreViewModel<UserSuggestionViewState,
|
||||
Never,
|
||||
UserSuggestionViewAction>
|
||||
|
||||
class UserSuggestionViewModel: UserSuggestionViewModelType, UserSuggestionViewModelProtocol {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -39,15 +38,15 @@ class UserSuggestionViewModel: UserSuggestionViewModelType, UserSuggestionViewMo
|
||||
self.userSuggestionService = userSuggestionService
|
||||
|
||||
let items = userSuggestionService.items.value.map { suggestionItem in
|
||||
return UserSuggestionViewStateItem(id: suggestionItem.userId, avatar: suggestionItem, displayName: suggestionItem.displayName)
|
||||
UserSuggestionViewStateItem(id: suggestionItem.userId, avatar: suggestionItem, displayName: suggestionItem.displayName)
|
||||
}
|
||||
|
||||
super.init(initialViewState: UserSuggestionViewState(items: items))
|
||||
|
||||
userSuggestionService.items.sink { [weak self] items in
|
||||
self?.state.items = items.map({ item in
|
||||
self?.state.items = items.map { item in
|
||||
UserSuggestionViewStateItem(id: item.userId, avatar: item, displayName: item.displayName)
|
||||
})
|
||||
}
|
||||
}.store(in: &cancellables)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,7 @@
|
||||
import SwiftUI
|
||||
|
||||
struct UserSuggestionList: View {
|
||||
private struct Constants {
|
||||
private enum Constants {
|
||||
static let topPadding: CGFloat = 8.0
|
||||
static let listItemPadding: CGFloat = 4.0
|
||||
static let lineSpacing: CGFloat = 10.0
|
||||
@@ -57,7 +57,7 @@ struct UserSuggestionList: View {
|
||||
userId: item.id
|
||||
)
|
||||
.padding(.bottom, Constants.listItemPadding)
|
||||
.padding(.top, (viewModel.viewState.items.first?.id == item.id ? Constants.listItemPadding + Constants.topPadding : Constants.listItemPadding))
|
||||
.padding(.top, viewModel.viewState.items.first?.id == item.id ? Constants.listItemPadding + Constants.topPadding : Constants.listItemPadding)
|
||||
}
|
||||
}
|
||||
.listStyle(PlainListStyle())
|
||||
@@ -76,7 +76,6 @@ struct UserSuggestionList: View {
|
||||
}
|
||||
|
||||
private struct BackgroundView<Content: View>: View {
|
||||
|
||||
var content: () -> Content
|
||||
|
||||
@Environment(\.theme) private var theme: ThemeSwiftUI
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,13 +17,14 @@
|
||||
import SwiftUI
|
||||
|
||||
struct UserSuggestionListItem: View {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
|
||||
@Environment(\.theme) private var theme: ThemeSwiftUI
|
||||
|
||||
// MARK: Public
|
||||
|
||||
let avatar: AvatarInputProtocol?
|
||||
let displayName: String?
|
||||
let userId: String
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -18,11 +18,10 @@ import SwiftUI
|
||||
|
||||
struct UserSuggestionListWithInputViewModel {
|
||||
let listViewModel: UserSuggestionViewModel
|
||||
let callback: (String)->()
|
||||
let callback: (String) -> Void
|
||||
}
|
||||
|
||||
struct UserSuggestionListWithInput: View {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -30,14 +29,14 @@ struct UserSuggestionListWithInput: View {
|
||||
// MARK: Public
|
||||
|
||||
var viewModel: UserSuggestionListWithInputViewModel
|
||||
@State private var inputText: String = ""
|
||||
@State private var inputText = ""
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0.0) {
|
||||
UserSuggestionList(viewModel: viewModel.listViewModel.context)
|
||||
TextField("Search for user", text: $inputText)
|
||||
.background(Color.white)
|
||||
.onChange(of: inputText, perform:viewModel.callback)
|
||||
.onChange(of: inputText, perform: viewModel.callback)
|
||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||
.padding([.leading, .trailing])
|
||||
.onAppear {
|
||||
|
||||
Reference in New Issue
Block a user