mirror of
https://github.com/vector-im/element-ios.git
synced 2024-09-28 23:32:41 +00:00
Merge branch 'develop' into andy/4829_activity_indicators
This commit is contained in:
commit
18af47ad34
66 changed files with 902 additions and 104 deletions
12
CHANGES.md
12
CHANGES.md
|
@ -1,3 +1,15 @@
|
||||||
|
## Changes in 1.8.1 (2022-02-16)
|
||||||
|
|
||||||
|
🙌 Improvements
|
||||||
|
|
||||||
|
- Upgrade MatrixSDK version ([v0.22.1](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.22.1)).
|
||||||
|
|
||||||
|
🐛 Bugfixes
|
||||||
|
|
||||||
|
- Settings: Fix a bug where tapping a toggle could change multiple settings. ([#5463](https://github.com/vector-im/element-ios/issues/5463))
|
||||||
|
- Fix for images sometimes being sent unencrypted inside an encrypted room. ([#5564](https://github.com/vector-im/element-ios/issues/5564))
|
||||||
|
|
||||||
|
|
||||||
## Changes in 1.8.0 (2022-02-09)
|
## Changes in 1.8.0 (2022-02-09)
|
||||||
|
|
||||||
✨ Features
|
✨ Features
|
||||||
|
|
28
CommonKit/Common.xcconfig
Normal file
28
CommonKit/Common.xcconfig
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021 Vector Creations Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Configuration settings file format documentation can be found at:
|
||||||
|
// https://help.apple.com/xcode/#/dev745c5c974
|
||||||
|
|
||||||
|
#include "Config/AppIdentifiers.xcconfig"
|
||||||
|
#include "Config/AppVersion.xcconfig"
|
||||||
|
|
||||||
|
PRODUCT_NAME = CommonKit
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = $(BASE_BUNDLE_IDENTIFIER).commonkit
|
||||||
|
|
||||||
|
INFOPLIST_FILE = CommonKit/Info.plist
|
||||||
|
|
||||||
|
SKIP_INSTALL = YES
|
27
CommonKit/CommonKit.h
Normal file
27
CommonKit/CommonKit.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
//! Project version number for CommonKit.
|
||||||
|
FOUNDATION_EXPORT double CommonKitVersionNumber;
|
||||||
|
|
||||||
|
//! Project version string for CommonKit.
|
||||||
|
FOUNDATION_EXPORT const unsigned char CommonKitVersionString[];
|
||||||
|
|
||||||
|
// In this header, you should import all the public headers of your framework using statements like #import <CommonKit/PublicHeader.h>
|
||||||
|
|
||||||
|
|
20
CommonKit/Debug.xcconfig
Normal file
20
CommonKit/Debug.xcconfig
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021 Vector Creations Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Configuration settings file format documentation can be found at:
|
||||||
|
// https://help.apple.com/xcode/#/dev745c5c974
|
||||||
|
|
||||||
|
#include "Common.xcconfig"
|
22
CommonKit/Info.plist
Normal file
22
CommonKit/Info.plist
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>$(MARKETING_VERSION)</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
20
CommonKit/Release.xcconfig
Normal file
20
CommonKit/Release.xcconfig
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021 Vector Creations Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Configuration settings file format documentation can be found at:
|
||||||
|
// https://help.apple.com/xcode/#/dev745c5c974
|
||||||
|
|
||||||
|
#include "Common.xcconfig"
|
94
CommonKit/Source/Activity/Activity.swift
Normal file
94
CommonKit/Source/Activity/Activity.swift
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
/// An `Activity` represents the state of a temporary visual indicator, such as activity indicator, success notification or an error message. It does not directly manage the UI, instead it delegates to a `presenter`
|
||||||
|
/// whenever the UI should be shown or hidden.
|
||||||
|
///
|
||||||
|
/// More than one `Activity` may be requested by the system at the same time (e.g. global syncing vs local refresh),
|
||||||
|
/// and the `ActivityCenter` will ensure that only one activity is shown at a given time, putting the other in a pending queue.
|
||||||
|
///
|
||||||
|
/// A client that requests an activity can specify a default timeout after which the activity is dismissed, or it has to be manually
|
||||||
|
/// responsible for dismissing it via `cancel` method, or by deallocating itself.
|
||||||
|
public class Activity {
|
||||||
|
enum State {
|
||||||
|
case pending
|
||||||
|
case executing
|
||||||
|
case completed
|
||||||
|
}
|
||||||
|
|
||||||
|
private let request: ActivityRequest
|
||||||
|
private let completion: () -> Void
|
||||||
|
|
||||||
|
private(set) var state: State
|
||||||
|
|
||||||
|
public init(request: ActivityRequest, completion: @escaping () -> Void) {
|
||||||
|
self.request = request
|
||||||
|
self.completion = completion
|
||||||
|
|
||||||
|
state = .pending
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal func start() {
|
||||||
|
guard state == .pending else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
state = .executing
|
||||||
|
request.presenter.present()
|
||||||
|
|
||||||
|
switch request.dismissal {
|
||||||
|
case .manual:
|
||||||
|
break
|
||||||
|
case .timeout(let interval):
|
||||||
|
Timer.scheduledTimer(withTimeInterval: interval, repeats: false) { [weak self] _ in
|
||||||
|
self?.complete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cancel the activity, triggering any dismissal action / animation
|
||||||
|
///
|
||||||
|
/// Note: clients can call this method directly, if they have access to the `Activity`.
|
||||||
|
/// Once cancelled, `ActivityCenter` will automatically start the next `Activity` in the queue.
|
||||||
|
func cancel() {
|
||||||
|
complete()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func complete() {
|
||||||
|
guard state != .completed else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if state == .executing {
|
||||||
|
request.presenter.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
state = .completed
|
||||||
|
completion()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public extension Activity {
|
||||||
|
func store<C>(in collection: inout C) where C: RangeReplaceableCollection, C.Element == Activity {
|
||||||
|
collection.append(self)
|
||||||
|
}
|
||||||
|
}
|
60
CommonKit/Source/Activity/ActivityCenter.swift
Normal file
60
CommonKit/Source/Activity/ActivityCenter.swift
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// A shared activity center with a single FIFO queue which will ensure only one activity is shown at a given time.
|
||||||
|
///
|
||||||
|
/// `ActivityCenter` offers a `shared` center that can be used by any clients, but clients are also allowed
|
||||||
|
/// to create local `ActivityCenter` if the context requres multiple simultaneous activities.
|
||||||
|
public class ActivityCenter {
|
||||||
|
private class Weak<T: AnyObject> {
|
||||||
|
weak var element: T?
|
||||||
|
init(_ element: T) {
|
||||||
|
self.element = element
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static let shared = ActivityCenter()
|
||||||
|
private var queue = [Weak<Activity>]()
|
||||||
|
|
||||||
|
/// Add a new activity to the queue by providing a request.
|
||||||
|
///
|
||||||
|
/// The queue will start the activity right away, if there are no currently running activities,
|
||||||
|
/// otherwise the activity will be put on hold.
|
||||||
|
public func add(_ request: ActivityRequest) -> Activity {
|
||||||
|
let activity = Activity(request: request) { [weak self] in
|
||||||
|
self?.startNextIfIdle()
|
||||||
|
}
|
||||||
|
|
||||||
|
queue.append(Weak(activity))
|
||||||
|
startNextIfIdle()
|
||||||
|
return activity
|
||||||
|
}
|
||||||
|
|
||||||
|
private func startNextIfIdle() {
|
||||||
|
cleanup()
|
||||||
|
if let activity = queue.first?.element, activity.state == .pending {
|
||||||
|
activity.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func cleanup() {
|
||||||
|
queue.removeAll {
|
||||||
|
$0.element == nil || $0.element?.state == .completed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
CommonKit/Source/Activity/ActivityDismissal.swift
Normal file
25
CommonKit/Source/Activity/ActivityDismissal.swift
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// Different ways in which an `Activity` can be dismissed
|
||||||
|
public enum ActivityDismissal {
|
||||||
|
/// The `Activity` will not manage the dismissal, but will expect the calling client to do so manually
|
||||||
|
case manual
|
||||||
|
/// The `Activity` will be automatically dismissed after `TimeInterval`
|
||||||
|
case timeout(TimeInterval)
|
||||||
|
}
|
25
CommonKit/Source/Activity/ActivityPresentable.swift
Normal file
25
CommonKit/Source/Activity/ActivityPresentable.swift
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// A presenter associated with and called by an `Activity`, and responsible for the underlying view shown on the screen.
|
||||||
|
public protocol ActivityPresentable {
|
||||||
|
/// Called when the `Activity` is started (manually or by the `ActivityCenter`)
|
||||||
|
func present()
|
||||||
|
/// Called when the `Activity` is manually cancelled or completed
|
||||||
|
func dismiss()
|
||||||
|
}
|
28
CommonKit/Source/Activity/ActivityRequest.swift
Normal file
28
CommonKit/Source/Activity/ActivityRequest.swift
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// A request used to create an underlying `Activity`, allowing clients to only specify the visual aspects of an activity.
|
||||||
|
public struct ActivityRequest {
|
||||||
|
internal let presenter: ActivityPresentable
|
||||||
|
internal let dismissal: ActivityDismissal
|
||||||
|
|
||||||
|
public init(presenter: ActivityPresentable, dismissal: ActivityDismissal) {
|
||||||
|
self.presenter = presenter
|
||||||
|
self.dismissal = dismissal
|
||||||
|
}
|
||||||
|
}
|
55
CommonKit/Source/Activity/Tests/ActivityCenterTests.swift
Normal file
55
CommonKit/Source/Activity/Tests/ActivityCenterTests.swift
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
class ActivityCenterTests: XCTestCase {
|
||||||
|
var activities: [Activity]!
|
||||||
|
var center: ActivityCenter!
|
||||||
|
|
||||||
|
override func setUp() {
|
||||||
|
activities = []
|
||||||
|
center = ActivityCenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeRequest() -> ActivityRequest {
|
||||||
|
return ActivityRequest(
|
||||||
|
presenter: ActivityPresenterSpy(),
|
||||||
|
dismissal: .manual
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testStartsActivityWhenAdded() {
|
||||||
|
let activity = center.add(makeRequest())
|
||||||
|
XCTAssertEqual(activity.state, .executing)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSecondActivityIsPending() {
|
||||||
|
center.add(makeRequest()).store(in: &activities)
|
||||||
|
let activity = center.add(makeRequest())
|
||||||
|
XCTAssertEqual(activity.state, .pending)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSecondActivityIsExecutingWhenFirstCompleted() {
|
||||||
|
let first = center.add(makeRequest())
|
||||||
|
let second = center.add(makeRequest())
|
||||||
|
|
||||||
|
first.cancel()
|
||||||
|
|
||||||
|
XCTAssertEqual(second.state, .executing)
|
||||||
|
}
|
||||||
|
}
|
29
CommonKit/Source/Activity/Tests/ActivityPresenterSpy.swift
Normal file
29
CommonKit/Source/Activity/Tests/ActivityPresenterSpy.swift
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class ActivityPresenterSpy: ActivityPresentable {
|
||||||
|
var intel = [String]()
|
||||||
|
|
||||||
|
func present() {
|
||||||
|
intel.append(#function)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dismiss() {
|
||||||
|
intel.append(#function)
|
||||||
|
}
|
||||||
|
}
|
127
CommonKit/Source/Activity/Tests/ActivityTests.swift
Normal file
127
CommonKit/Source/Activity/Tests/ActivityTests.swift
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
class ActivityTests: XCTestCase {
|
||||||
|
var presenter: ActivityPresenterSpy!
|
||||||
|
|
||||||
|
override func setUp() {
|
||||||
|
super.setUp()
|
||||||
|
presenter = ActivityPresenterSpy()
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeActivity(dismissal: ActivityDismissal = .manual, callback: @escaping () -> Void = {}) -> Activity {
|
||||||
|
let request = ActivityRequest(
|
||||||
|
presenter: presenter,
|
||||||
|
dismissal: dismissal
|
||||||
|
)
|
||||||
|
return Activity(
|
||||||
|
request: request,
|
||||||
|
completion: callback
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - State
|
||||||
|
|
||||||
|
func testNewActivityIsPending() {
|
||||||
|
let activity = makeActivity()
|
||||||
|
XCTAssertEqual(activity.state, .pending)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testStartedActivityIsExecuting() {
|
||||||
|
let activity = makeActivity()
|
||||||
|
activity.start()
|
||||||
|
XCTAssertEqual(activity.state, .executing)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCancelledActivityIsCompleted() {
|
||||||
|
let activity = makeActivity()
|
||||||
|
activity.cancel()
|
||||||
|
XCTAssertEqual(activity.state, .completed)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Presenter
|
||||||
|
|
||||||
|
func testStartingActivityPresentsUI() {
|
||||||
|
let activity = makeActivity()
|
||||||
|
activity.start()
|
||||||
|
XCTAssertEqual(presenter.intel, ["present()"])
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAllowStartingOnlyOnce() {
|
||||||
|
let activity = makeActivity()
|
||||||
|
activity.start()
|
||||||
|
presenter.intel = []
|
||||||
|
|
||||||
|
activity.start()
|
||||||
|
|
||||||
|
XCTAssertEqual(presenter.intel, [])
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCancellingActivityDismissesUI() {
|
||||||
|
let activity = makeActivity()
|
||||||
|
activity.start()
|
||||||
|
presenter.intel = []
|
||||||
|
|
||||||
|
activity.cancel()
|
||||||
|
|
||||||
|
XCTAssertEqual(presenter.intel, ["dismiss()"])
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAllowCancellingOnlyOnce() {
|
||||||
|
let activity = makeActivity()
|
||||||
|
activity.start()
|
||||||
|
activity.cancel()
|
||||||
|
presenter.intel = []
|
||||||
|
|
||||||
|
activity.cancel()
|
||||||
|
|
||||||
|
XCTAssertEqual(presenter.intel, [])
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Dismissal
|
||||||
|
|
||||||
|
func testDismissAfterTimeout() {
|
||||||
|
let interval: TimeInterval = 0.01
|
||||||
|
let activity = makeActivity(dismissal: .timeout(interval))
|
||||||
|
|
||||||
|
activity.start()
|
||||||
|
|
||||||
|
let exp = expectation(description: "")
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + interval) {
|
||||||
|
exp.fulfill()
|
||||||
|
}
|
||||||
|
waitForExpectations(timeout: 1)
|
||||||
|
|
||||||
|
XCTAssertEqual(activity.state, .completed)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Completion callback
|
||||||
|
|
||||||
|
func testTriggersCallbackWhenCompleted() {
|
||||||
|
var didComplete = false
|
||||||
|
let activity = makeActivity {
|
||||||
|
didComplete = true
|
||||||
|
}
|
||||||
|
activity.start()
|
||||||
|
|
||||||
|
activity.cancel()
|
||||||
|
|
||||||
|
XCTAssertTrue(didComplete)
|
||||||
|
}
|
||||||
|
}
|
40
CommonKit/target.yml
Normal file
40
CommonKit/target.yml
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
name: CommonKit
|
||||||
|
|
||||||
|
schemes:
|
||||||
|
CommonKit:
|
||||||
|
analyze:
|
||||||
|
config: Debug
|
||||||
|
archive:
|
||||||
|
config: Release
|
||||||
|
build:
|
||||||
|
targets:
|
||||||
|
CommonKit:
|
||||||
|
- running
|
||||||
|
- testing
|
||||||
|
- profiling
|
||||||
|
- analyzing
|
||||||
|
- archiving
|
||||||
|
profile:
|
||||||
|
config: Release
|
||||||
|
run:
|
||||||
|
config: Debug
|
||||||
|
disableMainThreadChecker: true
|
||||||
|
test:
|
||||||
|
config: Debug
|
||||||
|
disableMainThreadChecker: true
|
||||||
|
targets:
|
||||||
|
- CommonKitUnitTests
|
||||||
|
|
||||||
|
targets:
|
||||||
|
CommonKit:
|
||||||
|
type: framework
|
||||||
|
platform: iOS
|
||||||
|
|
||||||
|
configFiles:
|
||||||
|
Debug: Debug.xcconfig
|
||||||
|
Release: Release.xcconfig
|
||||||
|
|
||||||
|
sources:
|
||||||
|
- path: .
|
||||||
|
excludes:
|
||||||
|
- "**/Tests/**"
|
42
CommonKit/targetUnitTests.yml
Normal file
42
CommonKit/targetUnitTests.yml
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
name: CommonKitUnitTests
|
||||||
|
|
||||||
|
schemes:
|
||||||
|
CommonKitUnitTests:
|
||||||
|
analyze:
|
||||||
|
config: Debug
|
||||||
|
archive:
|
||||||
|
config: Release
|
||||||
|
build:
|
||||||
|
targets:
|
||||||
|
CommonKitUnitTests:
|
||||||
|
- running
|
||||||
|
- testing
|
||||||
|
- profiling
|
||||||
|
- analyzing
|
||||||
|
- archiving
|
||||||
|
profile:
|
||||||
|
config: Release
|
||||||
|
run:
|
||||||
|
config: Debug
|
||||||
|
disableMainThreadChecker: true
|
||||||
|
test:
|
||||||
|
config: Debug
|
||||||
|
disableMainThreadChecker: true
|
||||||
|
targets:
|
||||||
|
- CommonKitUnitTests
|
||||||
|
|
||||||
|
targets:
|
||||||
|
CommonKitUnitTests:
|
||||||
|
type: bundle.unit-test
|
||||||
|
platform: iOS
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
- target: CommonKit
|
||||||
|
|
||||||
|
configFiles:
|
||||||
|
Debug: Debug.xcconfig
|
||||||
|
Release: Release.xcconfig
|
||||||
|
|
||||||
|
sources:
|
||||||
|
- path: .
|
||||||
|
|
|
@ -15,5 +15,5 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
// Version
|
// Version
|
||||||
MARKETING_VERSION = 1.8.1
|
MARKETING_VERSION = 1.8.2
|
||||||
CURRENT_PROJECT_VERSION = 1.8.1
|
CURRENT_PROJECT_VERSION = 1.8.2
|
||||||
|
|
4
Podfile
4
Podfile
|
@ -13,9 +13,9 @@ use_frameworks!
|
||||||
# - `{ :specHash => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for MatrixSDK repo. Used by Fastfile during CI
|
# - `{ :specHash => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for MatrixSDK repo. Used by Fastfile during CI
|
||||||
#
|
#
|
||||||
# Warning: our internal tooling depends on the name of this variable name, so be sure not to change it
|
# Warning: our internal tooling depends on the name of this variable name, so be sure not to change it
|
||||||
# $matrixSDKVersion = '= 0.22.0'
|
$matrixSDKVersion = '= 0.22.1'
|
||||||
# $matrixSDKVersion = :local
|
# $matrixSDKVersion = :local
|
||||||
$matrixSDKVersion = { :branch => 'develop'}
|
# $matrixSDKVersion = { :branch => 'develop'}
|
||||||
# $matrixSDKVersion = { :specHash => { git: 'https://git.io/fork123', branch: 'fix' } }
|
# $matrixSDKVersion = { :specHash => { git: 'https://git.io/fork123', branch: 'fix' } }
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
|
|
27
Podfile.lock
27
Podfile.lock
|
@ -45,6 +45,7 @@ PODS:
|
||||||
- GBDeviceInfo/Core (= 6.6.0)
|
- GBDeviceInfo/Core (= 6.6.0)
|
||||||
- GBDeviceInfo/Core (6.6.0)
|
- GBDeviceInfo/Core (6.6.0)
|
||||||
- GZIP (1.3.0)
|
- GZIP (1.3.0)
|
||||||
|
- HPGrowingTextView (1.1)
|
||||||
- Introspect (0.1.3)
|
- Introspect (0.1.3)
|
||||||
- JitsiMeetSDK (3.10.2)
|
- JitsiMeetSDK (3.10.2)
|
||||||
- KeychainAccess (4.2.2)
|
- KeychainAccess (4.2.2)
|
||||||
|
@ -56,16 +57,16 @@ PODS:
|
||||||
- LoggerAPI (1.9.200):
|
- LoggerAPI (1.9.200):
|
||||||
- Logging (~> 1.1)
|
- Logging (~> 1.1)
|
||||||
- Logging (1.4.0)
|
- Logging (1.4.0)
|
||||||
- MatrixSDK (0.22.0):
|
- MatrixSDK (0.22.1):
|
||||||
- MatrixSDK/Core (= 0.22.0)
|
- MatrixSDK/Core (= 0.22.1)
|
||||||
- MatrixSDK/Core (0.22.0):
|
- MatrixSDK/Core (0.22.1):
|
||||||
- AFNetworking (~> 4.0.0)
|
- AFNetworking (~> 4.0.0)
|
||||||
- GZIP (~> 1.3.0)
|
- GZIP (~> 1.3.0)
|
||||||
- libbase58 (~> 0.1.4)
|
- libbase58 (~> 0.1.4)
|
||||||
- OLMKit (~> 3.2.5)
|
- OLMKit (~> 3.2.5)
|
||||||
- Realm (= 10.16.0)
|
- Realm (= 10.16.0)
|
||||||
- SwiftyBeaver (= 1.9.5)
|
- SwiftyBeaver (= 1.9.5)
|
||||||
- MatrixSDK/JingleCallStack (0.22.0):
|
- MatrixSDK/JingleCallStack (0.22.1):
|
||||||
- JitsiMeetSDK (= 3.10.2)
|
- JitsiMeetSDK (= 3.10.2)
|
||||||
- MatrixSDK/Core
|
- MatrixSDK/Core
|
||||||
- OLMKit (3.2.5):
|
- OLMKit (3.2.5):
|
||||||
|
@ -111,12 +112,13 @@ DEPENDENCIES:
|
||||||
- FLEX (~> 4.5.0)
|
- FLEX (~> 4.5.0)
|
||||||
- FlowCommoniOS (~> 1.12.0)
|
- FlowCommoniOS (~> 1.12.0)
|
||||||
- GBDeviceInfo (~> 6.6.0)
|
- GBDeviceInfo (~> 6.6.0)
|
||||||
|
- HPGrowingTextView (~> 1.1)
|
||||||
- Introspect (~> 0.1)
|
- Introspect (~> 0.1)
|
||||||
- KeychainAccess (~> 4.2.2)
|
- KeychainAccess (~> 4.2.2)
|
||||||
- KTCenterFlowLayout (~> 1.3.1)
|
- KTCenterFlowLayout (~> 1.3.1)
|
||||||
- libPhoneNumber-iOS (~> 0.9.13)
|
- libPhoneNumber-iOS (~> 0.9.13)
|
||||||
- MatrixSDK (from `https://github.com/matrix-org/matrix-ios-sdk.git`, branch `develop`)
|
- MatrixSDK (= 0.22.1)
|
||||||
- MatrixSDK/JingleCallStack (from `https://github.com/matrix-org/matrix-ios-sdk.git`, branch `develop`)
|
- MatrixSDK/JingleCallStack (= 0.22.1)
|
||||||
- OLMKit
|
- OLMKit
|
||||||
- PostHog (~> 1.4.4)
|
- PostHog (~> 1.4.4)
|
||||||
- ReadMoreTextView (~> 3.0.1)
|
- ReadMoreTextView (~> 3.0.1)
|
||||||
|
@ -147,6 +149,7 @@ SPEC REPOS:
|
||||||
- FlowCommoniOS
|
- FlowCommoniOS
|
||||||
- GBDeviceInfo
|
- GBDeviceInfo
|
||||||
- GZIP
|
- GZIP
|
||||||
|
- HPGrowingTextView
|
||||||
- Introspect
|
- Introspect
|
||||||
- JitsiMeetSDK
|
- JitsiMeetSDK
|
||||||
- KeychainAccess
|
- KeychainAccess
|
||||||
|
@ -156,6 +159,7 @@ SPEC REPOS:
|
||||||
- libPhoneNumber-iOS
|
- libPhoneNumber-iOS
|
||||||
- LoggerAPI
|
- LoggerAPI
|
||||||
- Logging
|
- Logging
|
||||||
|
- MatrixSDK
|
||||||
- OLMKit
|
- OLMKit
|
||||||
- PostHog
|
- PostHog
|
||||||
- ReadMoreTextView
|
- ReadMoreTextView
|
||||||
|
@ -176,17 +180,11 @@ EXTERNAL SOURCES:
|
||||||
AnalyticsEvents:
|
AnalyticsEvents:
|
||||||
:branch: release/swift
|
:branch: release/swift
|
||||||
:git: https://github.com/matrix-org/matrix-analytics-events.git
|
:git: https://github.com/matrix-org/matrix-analytics-events.git
|
||||||
MatrixSDK:
|
|
||||||
:branch: develop
|
|
||||||
:git: https://github.com/matrix-org/matrix-ios-sdk.git
|
|
||||||
|
|
||||||
CHECKOUT OPTIONS:
|
CHECKOUT OPTIONS:
|
||||||
AnalyticsEvents:
|
AnalyticsEvents:
|
||||||
:commit: 8058dc6ec07ce0acfe5fdb19eb7e309b0c13845c
|
:commit: 8058dc6ec07ce0acfe5fdb19eb7e309b0c13845c
|
||||||
:git: https://github.com/matrix-org/matrix-analytics-events.git
|
:git: https://github.com/matrix-org/matrix-analytics-events.git
|
||||||
MatrixSDK:
|
|
||||||
:commit: 7be07981c3f2932b0205797f234982ca32da7dff
|
|
||||||
:git: https://github.com/matrix-org/matrix-ios-sdk.git
|
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce
|
AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce
|
||||||
|
@ -204,6 +202,7 @@ SPEC CHECKSUMS:
|
||||||
FlowCommoniOS: ca92071ab526dc89905495a37844fd7e78d1a7f2
|
FlowCommoniOS: ca92071ab526dc89905495a37844fd7e78d1a7f2
|
||||||
GBDeviceInfo: ed0db16230d2fa280e1cbb39a5a7f60f6946aaec
|
GBDeviceInfo: ed0db16230d2fa280e1cbb39a5a7f60f6946aaec
|
||||||
GZIP: 416858efbe66b41b206895ac6dfd5493200d95b3
|
GZIP: 416858efbe66b41b206895ac6dfd5493200d95b3
|
||||||
|
HPGrowingTextView: 88a716d97fb853bcb08a4a08e4727da17efc9b19
|
||||||
Introspect: 2be020f30f084ada52bb4387fff83fa52c5c400e
|
Introspect: 2be020f30f084ada52bb4387fff83fa52c5c400e
|
||||||
JitsiMeetSDK: 2f118fa770f23e518f3560fc224fae3ac7062223
|
JitsiMeetSDK: 2f118fa770f23e518f3560fc224fae3ac7062223
|
||||||
KeychainAccess: c0c4f7f38f6fc7bbe58f5702e25f7bd2f65abf51
|
KeychainAccess: c0c4f7f38f6fc7bbe58f5702e25f7bd2f65abf51
|
||||||
|
@ -213,7 +212,7 @@ SPEC CHECKSUMS:
|
||||||
libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75
|
libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75
|
||||||
LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d
|
LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d
|
||||||
Logging: beeb016c9c80cf77042d62e83495816847ef108b
|
Logging: beeb016c9c80cf77042d62e83495816847ef108b
|
||||||
MatrixSDK: 21201cd007145d96beff24cc7f9727ced497c3fd
|
MatrixSDK: 12c1a56e037f629e493cbcd615fd13cfc58cee3a
|
||||||
OLMKit: 9fb4799c4a044dd2c06bda31ec31a12191ad30b5
|
OLMKit: 9fb4799c4a044dd2c06bda31ec31a12191ad30b5
|
||||||
PostHog: 4b6321b521569092d4ef3a02238d9435dbaeb99f
|
PostHog: 4b6321b521569092d4ef3a02238d9435dbaeb99f
|
||||||
ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d
|
ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d
|
||||||
|
@ -230,6 +229,6 @@ SPEC CHECKSUMS:
|
||||||
zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c
|
zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c
|
||||||
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
|
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
|
||||||
|
|
||||||
PODFILE CHECKSUM: 9b4be35779b652e3d0ad333d84069240ec58dc96
|
PODFILE CHECKSUM: ae70a46e98aae87f130ad3d246711fc6b6ae7286
|
||||||
|
|
||||||
COCOAPODS: 1.11.2
|
COCOAPODS: 1.11.2
|
||||||
|
|
23
Riot/Assets/Images.xcassets/Common/filter_off.imageset/Contents.json
vendored
Normal file
23
Riot/Assets/Images.xcassets/Common/filter_off.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "filter_off.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "filter_off@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "filter_off@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
Riot/Assets/Images.xcassets/Common/filter_off.imageset/filter_off.png
vendored
Normal file
BIN
Riot/Assets/Images.xcassets/Common/filter_off.imageset/filter_off.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 201 B |
BIN
Riot/Assets/Images.xcassets/Common/filter_off.imageset/filter_off@2x.png
vendored
Normal file
BIN
Riot/Assets/Images.xcassets/Common/filter_off.imageset/filter_off@2x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 297 B |
BIN
Riot/Assets/Images.xcassets/Common/filter_off.imageset/filter_off@3x.png
vendored
Normal file
BIN
Riot/Assets/Images.xcassets/Common/filter_off.imageset/filter_off@3x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 397 B |
23
Riot/Assets/Images.xcassets/Common/filter_on.imageset/Contents.json
vendored
Normal file
23
Riot/Assets/Images.xcassets/Common/filter_on.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "filter_on.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "filter_on@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "filter_on@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
Riot/Assets/Images.xcassets/Common/filter_on.imageset/filter_on.png
vendored
Normal file
BIN
Riot/Assets/Images.xcassets/Common/filter_on.imageset/filter_on.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 204 B |
BIN
Riot/Assets/Images.xcassets/Common/filter_on.imageset/filter_on@2x.png
vendored
Normal file
BIN
Riot/Assets/Images.xcassets/Common/filter_on.imageset/filter_on@2x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 295 B |
BIN
Riot/Assets/Images.xcassets/Common/filter_on.imageset/filter_on@3x.png
vendored
Normal file
BIN
Riot/Assets/Images.xcassets/Common/filter_on.imageset/filter_on@3x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 377 B |
|
@ -250,6 +250,7 @@ Tap the + to start adding people.";
|
||||||
"search_people" = "People";
|
"search_people" = "People";
|
||||||
"search_files" = "Files";
|
"search_files" = "Files";
|
||||||
"search_default_placeholder" = "Search";
|
"search_default_placeholder" = "Search";
|
||||||
|
"search_filter_placeholder" = "Filter";
|
||||||
"search_people_placeholder" = "Search by User ID, Name or email";
|
"search_people_placeholder" = "Search by User ID, Name or email";
|
||||||
"search_no_result" = "No results";
|
"search_no_result" = "No results";
|
||||||
"search_in_progress" = "Searching…";
|
"search_in_progress" = "Searching…";
|
||||||
|
@ -396,7 +397,7 @@ Tap the + to start adding people.";
|
||||||
"room_event_action_view_decrypted_source" = "View Decrypted Source";
|
"room_event_action_view_decrypted_source" = "View Decrypted Source";
|
||||||
"room_event_action_report" = "Report content";
|
"room_event_action_report" = "Report content";
|
||||||
"room_event_action_report_prompt_reason" = "Reason for reporting this content";
|
"room_event_action_report_prompt_reason" = "Reason for reporting this content";
|
||||||
"room_event_action_kick_prompt_reason" = "Reason for kicking this user";
|
"room_event_action_kick_prompt_reason" = "Reason for removing this user";
|
||||||
"room_event_action_ban_prompt_reason" = "Reason for banning this user";
|
"room_event_action_ban_prompt_reason" = "Reason for banning this user";
|
||||||
"room_event_action_report_prompt_ignore_user" = "Do you want to hide all messages from this user?";
|
"room_event_action_report_prompt_ignore_user" = "Do you want to hide all messages from this user?";
|
||||||
"room_event_action_save" = "Save";
|
"room_event_action_save" = "Save";
|
||||||
|
|
|
@ -63,6 +63,8 @@ internal class Asset: NSObject {
|
||||||
internal static let disclosureIcon = ImageAsset(name: "disclosure_icon")
|
internal static let disclosureIcon = ImageAsset(name: "disclosure_icon")
|
||||||
internal static let errorIcon = ImageAsset(name: "error_icon")
|
internal static let errorIcon = ImageAsset(name: "error_icon")
|
||||||
internal static let faceidIcon = ImageAsset(name: "faceid_icon")
|
internal static let faceidIcon = ImageAsset(name: "faceid_icon")
|
||||||
|
internal static let filterOff = ImageAsset(name: "filter_off")
|
||||||
|
internal static let filterOn = ImageAsset(name: "filter_on")
|
||||||
internal static let group = ImageAsset(name: "group")
|
internal static let group = ImageAsset(name: "group")
|
||||||
internal static let informationButton = ImageAsset(name: "information_button")
|
internal static let informationButton = ImageAsset(name: "information_button")
|
||||||
internal static let monitor = ImageAsset(name: "monitor")
|
internal static let monitor = ImageAsset(name: "monitor")
|
||||||
|
|
|
@ -467,7 +467,7 @@ public class MatrixKitL10n: NSObject {
|
||||||
public static var inviteUser: String {
|
public static var inviteUser: String {
|
||||||
return MatrixKitL10n.tr("invite_user")
|
return MatrixKitL10n.tr("invite_user")
|
||||||
}
|
}
|
||||||
/// Kick
|
/// Remove from chat
|
||||||
public static var kick: String {
|
public static var kick: String {
|
||||||
return MatrixKitL10n.tr("kick")
|
return MatrixKitL10n.tr("kick")
|
||||||
}
|
}
|
||||||
|
@ -1059,11 +1059,11 @@ public class MatrixKitL10n: NSObject {
|
||||||
public static func noticeRoomJoinRulePublicForDm(_ p1: String) -> String {
|
public static func noticeRoomJoinRulePublicForDm(_ p1: String) -> String {
|
||||||
return MatrixKitL10n.tr("notice_room_join_rule_public_for_dm", p1)
|
return MatrixKitL10n.tr("notice_room_join_rule_public_for_dm", p1)
|
||||||
}
|
}
|
||||||
/// %@ kicked %@
|
/// %@ removed %@
|
||||||
public static func noticeRoomKick(_ p1: String, _ p2: String) -> String {
|
public static func noticeRoomKick(_ p1: String, _ p2: String) -> String {
|
||||||
return MatrixKitL10n.tr("notice_room_kick", p1, p2)
|
return MatrixKitL10n.tr("notice_room_kick", p1, p2)
|
||||||
}
|
}
|
||||||
/// You kicked %@
|
/// You removed %@
|
||||||
public static func noticeRoomKickByYou(_ p1: String) -> String {
|
public static func noticeRoomKickByYou(_ p1: String) -> String {
|
||||||
return MatrixKitL10n.tr("notice_room_kick_by_you", p1)
|
return MatrixKitL10n.tr("notice_room_kick_by_you", p1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3259,7 +3259,7 @@ public class VectorL10n: NSObject {
|
||||||
public static var roomEventActionForward: String {
|
public static var roomEventActionForward: String {
|
||||||
return VectorL10n.tr("Vector", "room_event_action_forward")
|
return VectorL10n.tr("Vector", "room_event_action_forward")
|
||||||
}
|
}
|
||||||
/// Reason for kicking this user
|
/// Reason for removing this user
|
||||||
public static var roomEventActionKickPromptReason: String {
|
public static var roomEventActionKickPromptReason: String {
|
||||||
return VectorL10n.tr("Vector", "room_event_action_kick_prompt_reason")
|
return VectorL10n.tr("Vector", "room_event_action_kick_prompt_reason")
|
||||||
}
|
}
|
||||||
|
@ -4023,6 +4023,10 @@ public class VectorL10n: NSObject {
|
||||||
public static var searchFiles: String {
|
public static var searchFiles: String {
|
||||||
return VectorL10n.tr("Vector", "search_files")
|
return VectorL10n.tr("Vector", "search_files")
|
||||||
}
|
}
|
||||||
|
/// Filter
|
||||||
|
public static var searchFilterPlaceholder: String {
|
||||||
|
return VectorL10n.tr("Vector", "search_filter_placeholder")
|
||||||
|
}
|
||||||
/// Searching…
|
/// Searching…
|
||||||
public static var searchInProgress: String {
|
public static var searchInProgress: String {
|
||||||
return VectorL10n.tr("Vector", "search_in_progress")
|
return VectorL10n.tr("Vector", "search_in_progress")
|
||||||
|
|
|
@ -123,7 +123,11 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro
|
||||||
tableSearchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 600, 44)];
|
tableSearchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 600, 44)];
|
||||||
tableSearchBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
tableSearchBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||||
tableSearchBar.showsCancelButton = NO;
|
tableSearchBar.showsCancelButton = NO;
|
||||||
tableSearchBar.placeholder = [VectorL10n searchDefaultPlaceholder];
|
tableSearchBar.placeholder = [VectorL10n searchFilterPlaceholder];
|
||||||
|
[tableSearchBar setImage:AssetImages.filterOff.image
|
||||||
|
forSearchBarIcon:UISearchBarIconSearch
|
||||||
|
state:UIControlStateNormal];
|
||||||
|
|
||||||
tableSearchBar.delegate = self;
|
tableSearchBar.delegate = self;
|
||||||
|
|
||||||
displayedSectionHeaders = [NSMutableArray array];
|
displayedSectionHeaders = [NSMutableArray array];
|
||||||
|
@ -173,7 +177,10 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro
|
||||||
}];
|
}];
|
||||||
|
|
||||||
self.recentsSearchBar.autocapitalizationType = UITextAutocapitalizationTypeNone;
|
self.recentsSearchBar.autocapitalizationType = UITextAutocapitalizationTypeNone;
|
||||||
self.recentsSearchBar.placeholder = [VectorL10n searchDefaultPlaceholder];
|
self.recentsSearchBar.placeholder = [VectorL10n searchFilterPlaceholder];
|
||||||
|
[self.recentsSearchBar setImage:AssetImages.filterOff.image
|
||||||
|
forSearchBarIcon:UISearchBarIconSearch
|
||||||
|
state:UIControlStateNormal];
|
||||||
|
|
||||||
// Observe user interface theme change.
|
// Observe user interface theme change.
|
||||||
kThemeServiceDidChangeThemeNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kThemeServiceDidChangeThemeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
kThemeServiceDidChangeThemeNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kThemeServiceDidChangeThemeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||||
|
@ -2197,6 +2204,16 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro
|
||||||
[self.recentsSearchBar setShowsCancelButton:NO animated:NO];
|
[self.recentsSearchBar setShowsCancelButton:NO animated:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
|
||||||
|
{
|
||||||
|
[super searchBar:searchBar textDidChange:searchText];
|
||||||
|
|
||||||
|
UIImage *filterIcon = searchText.length > 0 ? AssetImages.filterOn.image : AssetImages.filterOff.image;
|
||||||
|
[self.recentsSearchBar setImage:filterIcon
|
||||||
|
forSearchBarIcon:UISearchBarIconSearch
|
||||||
|
state:UIControlStateNormal];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - CreateRoomCoordinatorBridgePresenterDelegate
|
#pragma mark - CreateRoomCoordinatorBridgePresenterDelegate
|
||||||
|
|
||||||
- (void)createRoomCoordinatorBridgePresenterDelegate:(CreateRoomCoordinatorBridgePresenter *)coordinatorBridgePresenter didCreateNewRoom:(MXRoom *)room
|
- (void)createRoomCoordinatorBridgePresenterDelegate:(CreateRoomCoordinatorBridgePresenter *)coordinatorBridgePresenter didCreateNewRoom:(MXRoom *)room
|
||||||
|
|
|
@ -160,7 +160,7 @@
|
||||||
threadParameters = [[ThreadParameters alloc] initWithThreadId:event.threadId
|
threadParameters = [[ThreadParameters alloc] initWithThreadId:event.threadId
|
||||||
stackRoomScreen:NO];
|
stackRoomScreen:NO];
|
||||||
}
|
}
|
||||||
else if ([self.mainSession.threadingService isEventThreadRoot:event])
|
else if (event.unsignedData.relations.thread || [self.mainSession.threadingService isEventThreadRoot:event])
|
||||||
{
|
{
|
||||||
threadParameters = [[ThreadParameters alloc] initWithThreadId:event.eventId
|
threadParameters = [[ThreadParameters alloc] initWithThreadId:event.eventId
|
||||||
stackRoomScreen:NO];
|
stackRoomScreen:NO];
|
||||||
|
|
|
@ -89,6 +89,10 @@
|
||||||
{
|
{
|
||||||
continueBlock();
|
continueBlock();
|
||||||
}
|
}
|
||||||
|
else if (result.result.unsignedData.relations.thread)
|
||||||
|
{
|
||||||
|
continueBlock();
|
||||||
|
}
|
||||||
else if (room)
|
else if (room)
|
||||||
{
|
{
|
||||||
[room liveTimeline:^(id<MXEventTimeline> liveTimeline) {
|
[room liveTimeline:^(id<MXEventTimeline> liveTimeline) {
|
||||||
|
@ -164,8 +168,9 @@
|
||||||
{
|
{
|
||||||
if (cellData.hasThreadRoot)
|
if (cellData.hasThreadRoot)
|
||||||
{
|
{
|
||||||
MXThread *thread = cellData.bubbleComponents.firstObject.thread;
|
id<MXThreadProtocol> thread = cellData.bubbleComponents.firstObject.thread;
|
||||||
ThreadSummaryView *threadSummaryView = [[ThreadSummaryView alloc] initWithThread:thread];
|
ThreadSummaryView *threadSummaryView = [[ThreadSummaryView alloc] initWithThread:thread
|
||||||
|
session:self.mxSession];
|
||||||
[bubbleCell.tmpSubviews addObject:threadSummaryView];
|
[bubbleCell.tmpSubviews addObject:threadSummaryView];
|
||||||
|
|
||||||
threadSummaryView.translatesAutoresizingMaskIntoConstraints = NO;
|
threadSummaryView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||||
|
|
|
@ -167,7 +167,7 @@
|
||||||
threadParameters = [[ThreadParameters alloc] initWithThreadId:event.threadId
|
threadParameters = [[ThreadParameters alloc] initWithThreadId:event.threadId
|
||||||
stackRoomScreen:NO];
|
stackRoomScreen:NO];
|
||||||
}
|
}
|
||||||
else if ([self.mainSession.threadingService isEventThreadRoot:event])
|
else if (event.unsignedData.relations.thread || [self.mainSession.threadingService isEventThreadRoot:event])
|
||||||
{
|
{
|
||||||
threadParameters = [[ThreadParameters alloc] initWithThreadId:event.eventId
|
threadParameters = [[ThreadParameters alloc] initWithThreadId:event.eventId
|
||||||
stackRoomScreen:NO];
|
stackRoomScreen:NO];
|
||||||
|
|
|
@ -367,7 +367,7 @@
|
||||||
"notice_room_join" = "%@ joined";
|
"notice_room_join" = "%@ joined";
|
||||||
"notice_room_leave" = "%@ left";
|
"notice_room_leave" = "%@ left";
|
||||||
"notice_room_reject" = "%@ rejected the invitation";
|
"notice_room_reject" = "%@ rejected the invitation";
|
||||||
"notice_room_kick" = "%@ kicked %@";
|
"notice_room_kick" = "%@ removed %@";
|
||||||
"notice_room_unban" = "%@ unbanned %@";
|
"notice_room_unban" = "%@ unbanned %@";
|
||||||
"notice_room_ban" = "%@ banned %@";
|
"notice_room_ban" = "%@ banned %@";
|
||||||
"notice_room_withdraw" = "%@ withdrew %@'s invitation";
|
"notice_room_withdraw" = "%@ withdrew %@'s invitation";
|
||||||
|
@ -399,7 +399,7 @@
|
||||||
"notice_room_join_by_you" = "You joined";
|
"notice_room_join_by_you" = "You joined";
|
||||||
"notice_room_leave_by_you" = "You left";
|
"notice_room_leave_by_you" = "You left";
|
||||||
"notice_room_reject_by_you" = "You rejected the invitation";
|
"notice_room_reject_by_you" = "You rejected the invitation";
|
||||||
"notice_room_kick_by_you" = "You kicked %@";
|
"notice_room_kick_by_you" = "You removed %@";
|
||||||
"notice_room_unban_by_you" = "You unbanned %@";
|
"notice_room_unban_by_you" = "You unbanned %@";
|
||||||
"notice_room_ban_by_you" = "You banned %@";
|
"notice_room_ban_by_you" = "You banned %@";
|
||||||
"notice_room_withdraw_by_you" = "You withdrew %@'s invitation";
|
"notice_room_withdraw_by_you" = "You withdrew %@'s invitation";
|
||||||
|
@ -479,7 +479,7 @@
|
||||||
"num_members_one" = "%@ user";
|
"num_members_one" = "%@ user";
|
||||||
"num_members_other" = "%@ users";
|
"num_members_other" = "%@ users";
|
||||||
"invite" = "Invite";
|
"invite" = "Invite";
|
||||||
"kick" = "Kick";
|
"kick" = "Remove from chat";
|
||||||
"ban" = "Ban";
|
"ban" = "Ban";
|
||||||
"unban" = "Un-ban";
|
"unban" = "Un-ban";
|
||||||
"message_unsaved_changes" = "There are unsaved changes. Leaving will discard them.";
|
"message_unsaved_changes" = "There are unsaved changes. Leaving will discard them.";
|
||||||
|
|
|
@ -1422,29 +1422,31 @@ static const CGFloat kLocalPreviewMargin = 20;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateProximityAndSleep
|
- (void)updateProximityAndSleep
|
||||||
{
|
{
|
||||||
BOOL inCall = (mxCall.state == MXCallStateConnected || mxCall.state == MXCallStateRinging || mxCall.state == MXCallStateInviteSent || mxCall.state == MXCallStateConnecting || mxCall.state == MXCallStateCreateOffer || mxCall.state == MXCallStateCreateAnswer);
|
BOOL inCall = (mxCall.state == MXCallStateConnected || mxCall.state == MXCallStateRinging || mxCall.state == MXCallStateInviteSent || mxCall.state == MXCallStateConnecting || mxCall.state == MXCallStateCreateOffer || mxCall.state == MXCallStateCreateAnswer);
|
||||||
|
|
||||||
if (inCall)
|
|
||||||
{
|
|
||||||
BOOL isBuiltInReceiverUsed = self.isBuiltInReceiverAudioOuput;
|
BOOL isBuiltInReceiverUsed = self.isBuiltInReceiverAudioOuput;
|
||||||
|
|
||||||
// Enable the proximity monitoring when the built in receiver is used as the audio output.
|
// Enable the proximity monitoring when the built in receiver is used as the audio output.
|
||||||
BOOL enableProxMonitoring = isBuiltInReceiverUsed;
|
BOOL enableProxMonitoring = inCall && isBuiltInReceiverUsed;
|
||||||
[[UIDevice currentDevice] setProximityMonitoringEnabled:enableProxMonitoring];
|
|
||||||
|
UIDevice *device = [UIDevice currentDevice];
|
||||||
|
if (device && device.isProximityMonitoringEnabled != enableProxMonitoring)
|
||||||
|
{
|
||||||
|
[device setProximityMonitoringEnabled:enableProxMonitoring];
|
||||||
|
}
|
||||||
|
|
||||||
// Disable the idle timer during a video call, or during a voice call which is performed with the built-in receiver.
|
// Disable the idle timer during a video call, or during a voice call which is performed with the built-in receiver.
|
||||||
// Note: if the device is locked, VoIP calling get dropped if an incoming GSM call is received.
|
// Note: if the device is locked, VoIP calling get dropped if an incoming GSM call is received.
|
||||||
BOOL disableIdleTimer = mxCall.isVideoCall || isBuiltInReceiverUsed;
|
BOOL disableIdleTimer = inCall && (mxCall.isVideoCall || isBuiltInReceiverUsed);
|
||||||
|
|
||||||
UIApplication *sharedApplication = [UIApplication performSelector:@selector(sharedApplication)];
|
UIApplication *sharedApplication = [UIApplication performSelector:@selector(sharedApplication)];
|
||||||
if (sharedApplication)
|
if (sharedApplication && sharedApplication.isIdleTimerDisabled != disableIdleTimer)
|
||||||
{
|
{
|
||||||
sharedApplication.idleTimerDisabled = disableIdleTimer;
|
sharedApplication.idleTimerDisabled = disableIdleTimer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
- (UIView *)createIncomingCallView
|
- (UIView *)createIncomingCallView
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#import "MXKEventFormatter.h"
|
#import "MXKEventFormatter.h"
|
||||||
#import "MXKURLPreviewDataProtocol.h"
|
#import "MXKURLPreviewDataProtocol.h"
|
||||||
|
|
||||||
@class MXThread;
|
@protocol MXThreadProtocol;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Flags to indicate if a fix is required at the display time.
|
Flags to indicate if a fix is required at the display time.
|
||||||
|
@ -108,7 +108,7 @@ typedef enum : NSUInteger {
|
||||||
/**
|
/**
|
||||||
Thread for the bubble component. Should only exist for thread root events.
|
Thread for the bubble component. Should only exist for thread root events.
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, readonly) MXThread *thread;
|
@property (nonatomic, readonly) id<MXThreadProtocol> thread;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Create a new `MXKRoomBubbleComponent` object based on a `MXEvent` instance.
|
Create a new `MXKRoomBubbleComponent` object based on a `MXEvent` instance.
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
@interface MXKRoomBubbleComponent ()
|
@interface MXKRoomBubbleComponent ()
|
||||||
|
|
||||||
@property (nonatomic, readwrite) MXThread *thread;
|
@property (nonatomic, readwrite) id<MXThreadProtocol> thread;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -70,8 +70,17 @@
|
||||||
|
|
||||||
[self updateLinkWithRoomState:roomState];
|
[self updateLinkWithRoomState:roomState];
|
||||||
|
|
||||||
|
if (event.unsignedData.relations.thread)
|
||||||
|
{
|
||||||
|
self.thread = [[MXThreadModel alloc] initWithRootEvent:event
|
||||||
|
notificationCount:0
|
||||||
|
highlightCount:0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
self.thread = [session.threadingService threadWithId:event.eventId];
|
self.thread = [session.threadingService threadWithId:event.eventId];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -955,7 +955,7 @@ static NSString *const kHTMLATagRegexPattern = @"<a href=\"(.*?)\">([^<]*)</a>";
|
||||||
}
|
}
|
||||||
if (event.content[@"kick"])
|
if (event.content[@"kick"])
|
||||||
{
|
{
|
||||||
displayText = [NSString stringWithFormat:@"%@\n\u2022 kick: %@", displayText, event.content[@"kick"]];
|
displayText = [NSString stringWithFormat:@"%@\n\u2022 remove: %@", displayText, event.content[@"kick"]];
|
||||||
}
|
}
|
||||||
if (event.content[@"redact"])
|
if (event.content[@"redact"])
|
||||||
{
|
{
|
||||||
|
|
|
@ -130,6 +130,6 @@
|
||||||
@param roomDataSource room data source instance
|
@param roomDataSource room data source instance
|
||||||
*/
|
*/
|
||||||
- (void)roomDataSource:(RoomDataSource * _Nonnull)roomDataSource
|
- (void)roomDataSource:(RoomDataSource * _Nonnull)roomDataSource
|
||||||
didTapThread:(MXThread * _Nonnull)thread;
|
didTapThread:(id<MXThreadProtocol> _Nonnull)thread;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -466,7 +466,8 @@ const CGFloat kTypingCellHeight = 24;
|
||||||
// display thread summary view if the component has a thread in the room timeline
|
// display thread summary view if the component has a thread in the room timeline
|
||||||
if (RiotSettings.shared.enableThreads && component.thread && !self.threadId)
|
if (RiotSettings.shared.enableThreads && component.thread && !self.threadId)
|
||||||
{
|
{
|
||||||
threadSummaryView = [[ThreadSummaryView alloc] initWithThread:component.thread];
|
threadSummaryView = [[ThreadSummaryView alloc] initWithThread:component.thread
|
||||||
|
session:self.mxSession];
|
||||||
threadSummaryView.delegate = self;
|
threadSummaryView.delegate = self;
|
||||||
threadSummaryView.tag = index;
|
threadSummaryView.tag = index;
|
||||||
|
|
||||||
|
|
|
@ -438,10 +438,17 @@ typedef NS_ENUM(NSUInteger, MXKRoomViewControllerJoinRoomResult) {
|
||||||
- (void)setBubbleTableViewContentOffset:(CGPoint)contentOffset animated:(BOOL)animated;
|
- (void)setBubbleTableViewContentOffset:(CGPoint)contentOffset animated:(BOOL)animated;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Handle typing notification.
|
Sends a typing notification with the specified timeout.
|
||||||
|
|
||||||
@param typing Flag indicating whether the user is typing or not.
|
@param typing Flag indicating whether the user is typing or not.
|
||||||
|
@param notificationTimeoutMS The length of time the typing notification is valid for
|
||||||
*/
|
*/
|
||||||
- (void)handleTypingNotification:(BOOL)typing;
|
- (void)sendTypingNotification:(BOOL)typing timeout:(NSUInteger)notificationTimeoutMS;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Share encryption keys in this room.
|
||||||
|
*/
|
||||||
|
- (void)shareEncryptionKeys;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -3326,7 +3326,7 @@
|
||||||
roomDataSource.partialTextMessage = inputToolbarView.textMessage;
|
roomDataSource.partialTextMessage = inputToolbarView.textMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self handleTypingNotification:typing];
|
[self handleTypingState:typing];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)roomInputToolbarView:(MXKRoomInputToolbarView*)toolbarView heightDidChanged:(CGFloat)height completion:(void (^)(BOOL finished))completion
|
- (void)roomInputToolbarView:(MXKRoomInputToolbarView*)toolbarView heightDidChanged:(CGFloat)height completion:(void (^)(BOOL finished))completion
|
||||||
|
@ -3447,7 +3447,7 @@
|
||||||
}
|
}
|
||||||
# pragma mark - Typing notification
|
# pragma mark - Typing notification
|
||||||
|
|
||||||
- (void)handleTypingNotification:(BOOL)typing
|
- (void)handleTypingState:(BOOL)typing
|
||||||
{
|
{
|
||||||
NSUInteger notificationTimeoutMS = -1;
|
NSUInteger notificationTimeoutMS = -1;
|
||||||
if (typing)
|
if (typing)
|
||||||
|
@ -3509,6 +3509,11 @@
|
||||||
lastTypingDate = nil;
|
lastTypingDate = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[self sendTypingNotification:typing timeout:notificationTimeoutMS];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sendTypingNotification:(BOOL)typing timeout:(NSUInteger)notificationTimeoutMS
|
||||||
|
{
|
||||||
MXWeakify(self);
|
MXWeakify(self);
|
||||||
|
|
||||||
// Send typing notification to server
|
// Send typing notification to server
|
||||||
|
@ -3539,7 +3544,7 @@
|
||||||
// Check whether a new typing event has been observed
|
// Check whether a new typing event has been observed
|
||||||
BOOL typing = (lastTypingDate != nil);
|
BOOL typing = (lastTypingDate != nil);
|
||||||
// Post a new typing notification
|
// Post a new typing notification
|
||||||
[self handleTypingNotification:typing];
|
[self handleTypingState:typing];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4283,7 +4283,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||||
[self updateTitleViewEncryptionDecoration];
|
[self updateTitleViewEncryptionDecoration];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)roomDataSource:(RoomDataSource *)roomDataSource didTapThread:(MXThread *)thread
|
- (void)roomDataSource:(RoomDataSource *)roomDataSource didTapThread:(id<MXThreadProtocol>)thread
|
||||||
{
|
{
|
||||||
[self openThreadWithId:thread.id];
|
[self openThreadWithId:thread.id];
|
||||||
}
|
}
|
||||||
|
@ -4564,6 +4564,15 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||||
[self.userSuggestionCoordinator processTextMessage:toolbarView.textMessage];
|
[self.userSuggestionCoordinator processTextMessage:toolbarView.textMessage];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)roomInputToolbarViewDidOpenActionMenu:(MXKRoomInputToolbarView*)toolbarView
|
||||||
|
{
|
||||||
|
// Consider opening the action menu as beginning to type and share encryption keys if requested.
|
||||||
|
if ([MXKAppSettings standardAppSettings].outboundGroupSessionKeyPreSharingStrategy == MXKKeyPreSharingWhenTyping)
|
||||||
|
{
|
||||||
|
[self shareEncryptionKeys];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - MXKRoomMemberDetailsViewControllerDelegate
|
#pragma mark - MXKRoomMemberDetailsViewControllerDelegate
|
||||||
|
|
||||||
- (void)roomMemberDetailsViewController:(MXKRoomMemberDetailsViewController *)roomMemberDetailsViewController startChatWithMemberId:(NSString *)matrixId completion:(void (^)(void))completion
|
- (void)roomMemberDetailsViewController:(MXKRoomMemberDetailsViewController *)roomMemberDetailsViewController startChatWithMemberId:(NSString *)matrixId completion:(void (^)(void))completion
|
||||||
|
|
|
@ -96,6 +96,10 @@
|
||||||
{
|
{
|
||||||
continueBlock();
|
continueBlock();
|
||||||
}
|
}
|
||||||
|
else if (result.result.unsignedData.relations.thread)
|
||||||
|
{
|
||||||
|
continueBlock();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
[roomDataSource.room liveTimeline:^(id<MXEventTimeline> liveTimeline) {
|
[roomDataSource.room liveTimeline:^(id<MXEventTimeline> liveTimeline) {
|
||||||
|
@ -143,8 +147,9 @@
|
||||||
{
|
{
|
||||||
if (cellData.hasThreadRoot)
|
if (cellData.hasThreadRoot)
|
||||||
{
|
{
|
||||||
MXThread *thread = cellData.bubbleComponents.firstObject.thread;
|
id<MXThreadProtocol> thread = cellData.bubbleComponents.firstObject.thread;
|
||||||
ThreadSummaryView *threadSummaryView = [[ThreadSummaryView alloc] initWithThread:thread];
|
ThreadSummaryView *threadSummaryView = [[ThreadSummaryView alloc] initWithThread:thread
|
||||||
|
session:self.mxSession];
|
||||||
[bubbleCell.tmpSubviews addObject:threadSummaryView];
|
[bubbleCell.tmpSubviews addObject:threadSummaryView];
|
||||||
|
|
||||||
threadSummaryView.translatesAutoresizingMaskIntoConstraints = NO;
|
threadSummaryView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||||
|
|
|
@ -165,7 +165,7 @@
|
||||||
threadParameters = [[ThreadParameters alloc] initWithThreadId:event.threadId
|
threadParameters = [[ThreadParameters alloc] initWithThreadId:event.threadId
|
||||||
stackRoomScreen:NO];
|
stackRoomScreen:NO];
|
||||||
}
|
}
|
||||||
else if ([self.mainSession.threadingService isEventThreadRoot:event])
|
else if (event.unsignedData.relations.thread || [self.mainSession.threadingService isEventThreadRoot:event])
|
||||||
{
|
{
|
||||||
threadParameters = [[ThreadParameters alloc] initWithThreadId:event.eventId
|
threadParameters = [[ThreadParameters alloc] initWithThreadId:event.eventId
|
||||||
stackRoomScreen:NO];
|
stackRoomScreen:NO];
|
||||||
|
|
|
@ -47,6 +47,13 @@ typedef enum : NSUInteger
|
||||||
*/
|
*/
|
||||||
- (void)roomInputToolbarViewDidChangeTextMessage:(MXKRoomInputToolbarView*)toolbarView;
|
- (void)roomInputToolbarViewDidChangeTextMessage:(MXKRoomInputToolbarView*)toolbarView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Inform the delegate that the action menu was opened.
|
||||||
|
|
||||||
|
@param toolbarView the room input toolbar view
|
||||||
|
*/
|
||||||
|
- (void)roomInputToolbarViewDidOpenActionMenu:(MXKRoomInputToolbarView*)toolbarView;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -429,6 +429,7 @@ static const NSTimeInterval kActionMenuComposerHeightAnimationDuration = .3;
|
||||||
if (_actionMenuOpened) {
|
if (_actionMenuOpened) {
|
||||||
self.actionsBar.hidden = NO;
|
self.actionsBar.hidden = NO;
|
||||||
[self.actionsBar animateWithShowIn:_actionMenuOpened completion:nil];
|
[self.actionsBar animateWithShowIn:_actionMenuOpened completion:nil];
|
||||||
|
[self.delegate roomInputToolbarViewDidOpenActionMenu:self];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,7 +38,8 @@ class ThreadSummaryView: UIView {
|
||||||
@IBOutlet private weak var lastMessageContentLabel: UILabel!
|
@IBOutlet private weak var lastMessageContentLabel: UILabel!
|
||||||
|
|
||||||
private var theme: Theme = ThemeService.shared().theme
|
private var theme: Theme = ThemeService.shared().theme
|
||||||
private(set) var thread: MXThread?
|
private(set) var thread: MXThreadProtocol?
|
||||||
|
private weak var session: MXSession?
|
||||||
|
|
||||||
private lazy var tapGestureRecognizer: UITapGestureRecognizer = {
|
private lazy var tapGestureRecognizer: UITapGestureRecognizer = {
|
||||||
return UITapGestureRecognizer(target: self, action: #selector(tapped(_:)))
|
return UITapGestureRecognizer(target: self, action: #selector(tapped(_:)))
|
||||||
|
@ -48,8 +49,9 @@ class ThreadSummaryView: UIView {
|
||||||
|
|
||||||
// MARK: - Setup
|
// MARK: - Setup
|
||||||
|
|
||||||
init(withThread thread: MXThread) {
|
init(withThread thread: MXThreadProtocol, session: MXSession) {
|
||||||
self.thread = thread
|
self.thread = thread
|
||||||
|
self.session = session
|
||||||
super.init(frame: CGRect(origin: .zero,
|
super.init(frame: CGRect(origin: .zero,
|
||||||
size: CGSize(width: Constants.viewDefaultWidth,
|
size: CGSize(width: Constants.viewDefaultWidth,
|
||||||
height: RoomBubbleCellLayout.threadSummaryViewHeight)))
|
height: RoomBubbleCellLayout.threadSummaryViewHeight)))
|
||||||
|
@ -59,7 +61,7 @@ class ThreadSummaryView: UIView {
|
||||||
translatesAutoresizingMaskIntoConstraints = false
|
translatesAutoresizingMaskIntoConstraints = false
|
||||||
}
|
}
|
||||||
|
|
||||||
static func contentViewHeight(forThread thread: MXThread?, fitting maxWidth: CGFloat) -> CGFloat {
|
static func contentViewHeight(forThread thread: MXThreadProtocol?, fitting maxWidth: CGFloat) -> CGFloat {
|
||||||
return RoomBubbleCellLayout.threadSummaryViewHeight
|
return RoomBubbleCellLayout.threadSummaryViewHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +95,7 @@ class ThreadSummaryView: UIView {
|
||||||
|
|
||||||
guard let thread = thread,
|
guard let thread = thread,
|
||||||
let lastMessage = thread.lastMessage,
|
let lastMessage = thread.lastMessage,
|
||||||
let session = thread.session,
|
let session = session,
|
||||||
let eventFormatter = session.roomSummaryUpdateDelegate as? MXKEventFormatter,
|
let eventFormatter = session.roomSummaryUpdateDelegate as? MXKEventFormatter,
|
||||||
let room = session.room(withRoomId: lastMessage.roomId) else {
|
let room = session.room(withRoomId: lastMessage.roomId) else {
|
||||||
lastMessageAvatarView.avatarImageView.image = nil
|
lastMessageAvatarView.avatarImageView.image = nil
|
||||||
|
|
|
@ -1997,7 +1997,7 @@ TableViewSectionsDelegate>
|
||||||
labelAndSwitchCell.mxkSwitch.onTintColor = ThemeService.shared.theme.tintColor;
|
labelAndSwitchCell.mxkSwitch.onTintColor = ThemeService.shared.theme.tintColor;
|
||||||
labelAndSwitchCell.mxkSwitch.enabled = YES;
|
labelAndSwitchCell.mxkSwitch.enabled = YES;
|
||||||
|
|
||||||
[labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleEnableURLPreviews:) forControlEvents:UIControlEventValueChanged];
|
[labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleEnableURLPreviews:) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
|
||||||
cell = labelAndSwitchCell;
|
cell = labelAndSwitchCell;
|
||||||
}
|
}
|
||||||
|
@ -2442,7 +2442,7 @@ TableViewSectionsDelegate>
|
||||||
labelAndSwitchCell.mxkSwitch.on = RiotSettings.shared.enableRingingForGroupCalls;
|
labelAndSwitchCell.mxkSwitch.on = RiotSettings.shared.enableRingingForGroupCalls;
|
||||||
labelAndSwitchCell.mxkSwitch.onTintColor = ThemeService.shared.theme.tintColor;
|
labelAndSwitchCell.mxkSwitch.onTintColor = ThemeService.shared.theme.tintColor;
|
||||||
|
|
||||||
[labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleEnableRingingForGroupCalls:) forControlEvents:UIControlEventValueChanged];
|
[labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleEnableRingingForGroupCalls:) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
|
||||||
cell = labelAndSwitchCell;
|
cell = labelAndSwitchCell;
|
||||||
}
|
}
|
||||||
|
@ -2454,7 +2454,7 @@ TableViewSectionsDelegate>
|
||||||
labelAndSwitchCell.mxkSwitch.on = RiotSettings.shared.enableThreads;
|
labelAndSwitchCell.mxkSwitch.on = RiotSettings.shared.enableThreads;
|
||||||
labelAndSwitchCell.mxkSwitch.onTintColor = ThemeService.shared.theme.tintColor;
|
labelAndSwitchCell.mxkSwitch.onTintColor = ThemeService.shared.theme.tintColor;
|
||||||
|
|
||||||
[labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleEnableThreads:) forControlEvents:UIControlEventValueChanged];
|
[labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleEnableThreads:) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
|
||||||
cell = labelAndSwitchCell;
|
cell = labelAndSwitchCell;
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ class ThreadViewController: RoomViewController {
|
||||||
super.onButtonPressed(sender)
|
super.onButtonPressed(sender)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func handleTypingNotification(_ typing: Bool) {
|
override func sendTypingNotification(_ typing: Bool, timeout notificationTimeoutMS: UInt) {
|
||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,11 +65,11 @@ extension ThreadListCoordinator: ThreadListViewModelCoordinatorDelegate {
|
||||||
self.delegate?.threadListCoordinatorDidLoadThreads(self)
|
self.delegate?.threadListCoordinatorDidLoadThreads(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
func threadListViewModelDidSelectThread(_ viewModel: ThreadListViewModelProtocol, thread: MXThread) {
|
func threadListViewModelDidSelectThread(_ viewModel: ThreadListViewModelProtocol, thread: MXThreadProtocol) {
|
||||||
self.delegate?.threadListCoordinatorDidSelectThread(self, thread: thread)
|
self.delegate?.threadListCoordinatorDidSelectThread(self, thread: thread)
|
||||||
}
|
}
|
||||||
|
|
||||||
func threadListViewModelDidSelectThreadViewInRoom(_ viewModel: ThreadListViewModelProtocol, thread: MXThread) {
|
func threadListViewModelDidSelectThreadViewInRoom(_ viewModel: ThreadListViewModelProtocol, thread: MXThreadProtocol) {
|
||||||
self.delegate?.threadListCoordinatorDidSelectRoom(self, roomId: thread.roomId, eventId: thread.id)
|
self.delegate?.threadListCoordinatorDidSelectRoom(self, roomId: thread.roomId, eventId: thread.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ import Foundation
|
||||||
|
|
||||||
protocol ThreadListCoordinatorDelegate: AnyObject {
|
protocol ThreadListCoordinatorDelegate: AnyObject {
|
||||||
func threadListCoordinatorDidLoadThreads(_ coordinator: ThreadListCoordinatorProtocol)
|
func threadListCoordinatorDidLoadThreads(_ coordinator: ThreadListCoordinatorProtocol)
|
||||||
func threadListCoordinatorDidSelectThread(_ coordinator: ThreadListCoordinatorProtocol, thread: MXThread)
|
func threadListCoordinatorDidSelectThread(_ coordinator: ThreadListCoordinatorProtocol, thread: MXThreadProtocol)
|
||||||
func threadListCoordinatorDidSelectRoom(_ coordinator: ThreadListCoordinatorProtocol, roomId: String, eventId: String)
|
func threadListCoordinatorDidSelectRoom(_ coordinator: ThreadListCoordinatorProtocol, roomId: String, eventId: String)
|
||||||
func threadListCoordinatorDidCancel(_ coordinator: ThreadListCoordinatorProtocol)
|
func threadListCoordinatorDidCancel(_ coordinator: ThreadListCoordinatorProtocol)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,12 +26,12 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
|
||||||
|
|
||||||
private let session: MXSession
|
private let session: MXSession
|
||||||
private let roomId: String
|
private let roomId: String
|
||||||
private var threads: [MXThread] = []
|
private var threads: [MXThreadProtocol] = []
|
||||||
private var eventFormatter: MXKEventFormatter?
|
private var eventFormatter: MXKEventFormatter?
|
||||||
private var roomState: MXRoomState?
|
private var roomState: MXRoomState?
|
||||||
|
|
||||||
private var currentOperation: MXHTTPOperation?
|
private var currentOperation: MXHTTPOperation?
|
||||||
private var longPressedThread: MXThread?
|
private var longPressedThread: MXThreadProtocol?
|
||||||
|
|
||||||
// MARK: Public
|
// MARK: Public
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
|
||||||
|
|
||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
private func model(forThread thread: MXThread) -> ThreadModel {
|
private func model(forThread thread: MXThreadProtocol) -> ThreadModel {
|
||||||
let rootAvatarViewData: AvatarViewData?
|
let rootAvatarViewData: AvatarViewData?
|
||||||
let rootMessageSender: MXUser?
|
let rootMessageSender: MXUser?
|
||||||
let lastAvatarViewData: AvatarViewData?
|
let lastAvatarViewData: AvatarViewData?
|
||||||
|
@ -199,7 +199,7 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
|
||||||
notificationStatus: notificationStatus)
|
notificationStatus: notificationStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func rootMessageText(forThread thread: MXThread) -> NSAttributedString? {
|
private func rootMessageText(forThread thread: MXThreadProtocol) -> NSAttributedString? {
|
||||||
guard let eventFormatter = eventFormatter else {
|
guard let eventFormatter = eventFormatter else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -229,7 +229,7 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
|
||||||
error: formatterError)
|
error: formatterError)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func lastMessageTextAndTime(forThread thread: MXThread) -> (NSAttributedString?, String?) {
|
private func lastMessageTextAndTime(forThread thread: MXThreadProtocol) -> (NSAttributedString?, String?) {
|
||||||
guard let eventFormatter = eventFormatter else {
|
guard let eventFormatter = eventFormatter else {
|
||||||
return (nil, nil)
|
return (nil, nil)
|
||||||
}
|
}
|
||||||
|
@ -251,22 +251,35 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
|
||||||
viewState = .loading
|
viewState = .loading
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let onlyParticipated: Bool
|
||||||
|
|
||||||
switch selectedFilterType {
|
switch selectedFilterType {
|
||||||
case .all:
|
case .all:
|
||||||
threads = session.threadingService.threads(inRoom: roomId)
|
onlyParticipated = false
|
||||||
case .myThreads:
|
case .myThreads:
|
||||||
threads = session.threadingService.participatedThreads(inRoom: roomId)
|
onlyParticipated = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session.threadingService.allThreads(inRoom: roomId,
|
||||||
|
onlyParticipated: onlyParticipated) { [weak self] response in
|
||||||
|
guard let self = self else { return }
|
||||||
|
switch response {
|
||||||
|
case .success(let threads):
|
||||||
|
self.threads = threads
|
||||||
|
self.threadsLoaded()
|
||||||
|
case .failure(let error):
|
||||||
|
MXLog.error("[ThreadListViewModel] loadData: error: \(error)")
|
||||||
|
self.viewState = .error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func threadsLoaded() {
|
||||||
if threads.isEmpty {
|
if threads.isEmpty {
|
||||||
viewState = .empty(emptyViewModel)
|
viewState = .empty(emptyViewModel)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
threadsLoaded()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func threadsLoaded() {
|
|
||||||
guard let eventFormatter = session.roomSummaryUpdateDelegate as? MXKEventFormatter,
|
guard let eventFormatter = session.roomSummaryUpdateDelegate as? MXKEventFormatter,
|
||||||
let room = session.room(withRoomId: roomId) else {
|
let room = session.room(withRoomId: roomId) else {
|
||||||
// go into loaded state
|
// go into loaded state
|
||||||
|
@ -323,7 +336,7 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
|
||||||
|
|
||||||
private func actionShare() {
|
private func actionShare() {
|
||||||
guard let thread = longPressedThread,
|
guard let thread = longPressedThread,
|
||||||
let index = threads.firstIndex(of: thread) else {
|
let index = threads.firstIndex(where: { thread.id == $0.id }) else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if let permalink = MXTools.permalink(toEvent: thread.id, inRoom: thread.roomId),
|
if let permalink = MXTools.permalink(toEvent: thread.id, inRoom: thread.roomId),
|
||||||
|
|
|
@ -24,8 +24,8 @@ protocol ThreadListViewModelViewDelegate: AnyObject {
|
||||||
|
|
||||||
protocol ThreadListViewModelCoordinatorDelegate: AnyObject {
|
protocol ThreadListViewModelCoordinatorDelegate: AnyObject {
|
||||||
func threadListViewModelDidLoadThreads(_ viewModel: ThreadListViewModelProtocol)
|
func threadListViewModelDidLoadThreads(_ viewModel: ThreadListViewModelProtocol)
|
||||||
func threadListViewModelDidSelectThread(_ viewModel: ThreadListViewModelProtocol, thread: MXThread)
|
func threadListViewModelDidSelectThread(_ viewModel: ThreadListViewModelProtocol, thread: MXThreadProtocol)
|
||||||
func threadListViewModelDidSelectThreadViewInRoom(_ viewModel: ThreadListViewModelProtocol, thread: MXThread)
|
func threadListViewModelDidSelectThreadViewInRoom(_ viewModel: ThreadListViewModelProtocol, thread: MXThreadProtocol)
|
||||||
func threadListViewModelDidCancel(_ viewModel: ThreadListViewModelProtocol)
|
func threadListViewModelDidCancel(_ viewModel: ThreadListViewModelProtocol)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ enum ThreadNotificationStatus {
|
||||||
case notified
|
case notified
|
||||||
case highlighted
|
case highlighted
|
||||||
|
|
||||||
init(withThread thread: MXThread) {
|
init(withThread thread: MXThreadProtocol) {
|
||||||
if thread.highlightCount > 0 {
|
if thread.highlightCount > 0 {
|
||||||
self = .highlighted
|
self = .highlighted
|
||||||
} else if thread.isParticipated && thread.notificationCount > 0 {
|
} else if thread.isParticipated && thread.notificationCount > 0 {
|
||||||
|
|
|
@ -153,7 +153,7 @@ extension ThreadsCoordinator: ThreadListCoordinatorDelegate {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func threadListCoordinatorDidSelectThread(_ coordinator: ThreadListCoordinatorProtocol, thread: MXThread) {
|
func threadListCoordinatorDidSelectThread(_ coordinator: ThreadListCoordinatorProtocol, thread: MXThreadProtocol) {
|
||||||
let roomCoordinator = createThreadCoordinator(forThreadId: thread.id)
|
let roomCoordinator = createThreadCoordinator(forThreadId: thread.id)
|
||||||
selectedThreadCoordinator = roomCoordinator
|
selectedThreadCoordinator = roomCoordinator
|
||||||
roomCoordinator.start()
|
roomCoordinator.start()
|
||||||
|
|
|
@ -35,6 +35,7 @@ targets:
|
||||||
- target: SiriIntents
|
- target: SiriIntents
|
||||||
- target: RiotNSE
|
- target: RiotNSE
|
||||||
- target: DesignKit
|
- target: DesignKit
|
||||||
|
- target: CommonKit
|
||||||
- package: Mapbox
|
- package: Mapbox
|
||||||
|
|
||||||
configFiles:
|
configFiles:
|
||||||
|
|
1
changelog.d/4103.bugfix
Normal file
1
changelog.d/4103.bugfix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Fix proximity sensor staying on and sleep timer staying disabled after call ends
|
1
changelog.d/4829.change
Normal file
1
changelog.d/4829.change
Normal file
|
@ -0,0 +1 @@
|
||||||
|
CommonKit: Create a new framework with common functionality and create Activity and ActivityCenter
|
1
changelog.d/5250.change
Normal file
1
changelog.d/5250.change
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Filter: update placeholder text and icon
|
1
changelog.d/5346.bugfix
Normal file
1
changelog.d/5346.bugfix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Wordings: Replace "kick" and all affiliate word by "remove"
|
1
changelog.d/5540.change
Normal file
1
changelog.d/5540.change
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ThreadListViewModel: Use new apis to fetch threads.
|
1
changelog.d/5562.change
Normal file
1
changelog.d/5562.change
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Search: Use bundled aggregations if provided.
|
|
@ -35,6 +35,8 @@ include:
|
||||||
- path: RiotSwiftUI/target.yml
|
- path: RiotSwiftUI/target.yml
|
||||||
- path: RiotSwiftUI/targetUnitTests.yml
|
- path: RiotSwiftUI/targetUnitTests.yml
|
||||||
- path: RiotSwiftUI/targetUITests.yml
|
- path: RiotSwiftUI/targetUITests.yml
|
||||||
|
- path: CommonKit/target.yml
|
||||||
|
- path: CommonKit/targetUnitTests.yml
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
Mapbox:
|
Mapbox:
|
||||||
|
|
Loading…
Reference in a new issue