mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-05 11:58:32 +00:00
Removing Dead Code part 1 (#2234)
This commit is contained in:
@@ -45,6 +45,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
|
||||
|
||||
private var authenticationCoordinator: AuthenticationCoordinator?
|
||||
private let appLockFlowCoordinator: AppLockFlowCoordinator
|
||||
// periphery:ignore - used to avoid deallocation
|
||||
private var appLockSetupFlowCoordinator: AppLockSetupFlowCoordinator?
|
||||
private var userSessionFlowCoordinator: UserSessionFlowCoordinator?
|
||||
private var softLogoutCoordinator: SoftLogoutScreenCoordinator?
|
||||
@@ -90,7 +91,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
|
||||
|
||||
navigationRootCoordinator = NavigationRootCoordinator()
|
||||
|
||||
Self.setupServiceLocator(navigationRootCoordinator: navigationRootCoordinator, appSettings: appSettings)
|
||||
Self.setupServiceLocator(appSettings: appSettings)
|
||||
|
||||
ServiceLocator.shared.analytics.startIfEnabled()
|
||||
|
||||
@@ -209,9 +210,9 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
|
||||
|
||||
// MARK: - AuthenticationCoordinatorDelegate
|
||||
|
||||
func authenticationCoordinator(_ authenticationCoordinator: AuthenticationCoordinator, didLoginWithSession userSession: UserSessionProtocol) {
|
||||
func authenticationCoordinator(didLoginWithSession userSession: UserSessionProtocol) {
|
||||
self.userSession = userSession
|
||||
self.authenticationCoordinator = nil
|
||||
authenticationCoordinator = nil
|
||||
stateMachine.processEvent(.createdUserSession)
|
||||
}
|
||||
|
||||
@@ -232,7 +233,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
|
||||
UIApplication.shared.unregisterForRemoteNotifications()
|
||||
}
|
||||
|
||||
func shouldDisplayInAppNotification(_ service: NotificationManagerProtocol, content: UNNotificationContent) -> Bool {
|
||||
func shouldDisplayInAppNotification(content: UNNotificationContent) -> Bool {
|
||||
guard let roomID = content.roomID else {
|
||||
return true
|
||||
}
|
||||
@@ -243,7 +244,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
|
||||
return !userSessionFlowCoordinator.isDisplayingRoomScreen(withRoomID: roomID)
|
||||
}
|
||||
|
||||
func notificationTapped(_ service: NotificationManagerProtocol, content: UNNotificationContent) async {
|
||||
func notificationTapped(content: UNNotificationContent) async {
|
||||
MXLog.info("[AppCoordinator] tappedNotification")
|
||||
|
||||
guard let roomID = content.roomID,
|
||||
@@ -284,7 +285,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
|
||||
setenv("RUST_BACKTRACE", "1", 1)
|
||||
}
|
||||
|
||||
private static func setupServiceLocator(navigationRootCoordinator: NavigationRootCoordinator, appSettings: AppSettings) {
|
||||
private static func setupServiceLocator(appSettings: AppSettings) {
|
||||
ServiceLocator.shared.register(userIndicatorController: UserIndicatorController())
|
||||
ServiceLocator.shared.register(appSettings: appSettings)
|
||||
ServiceLocator.shared.register(networkMonitor: NetworkMonitor())
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
import Foundation
|
||||
|
||||
protocol AppCoordinatorProtocol: CoordinatorProtocol {
|
||||
var notificationManager: NotificationManagerProtocol { get }
|
||||
var windowManager: WindowManager { get }
|
||||
@discardableResult func handleDeepLink(_ url: URL) -> Bool
|
||||
}
|
||||
|
||||
@@ -86,8 +86,6 @@ final class AppSettings {
|
||||
/// deleted between runs so should clear data in the shared container and keychain.
|
||||
@UserPreference(key: UserDefaultsKeys.lastVersionLaunched, storageType: .userDefaults(store))
|
||||
var lastVersionLaunched: String?
|
||||
|
||||
let lastLaunchDate = Date()
|
||||
|
||||
/// The Set of room identifiers of invites that the user already saw in the invites list.
|
||||
/// This Set is being used to implement badges for unread invites.
|
||||
@@ -180,7 +178,6 @@ final class AppSettings {
|
||||
let bugReportSentryURL: URL = "https://f39ac49e97714316965b777d9f3d6cd8@sentry.tools.element.io/44"
|
||||
// Use the name allocated by the bug report server
|
||||
let bugReportApplicationId = "element-x-ios"
|
||||
let bugReportUISIId = "element-auto-uisi"
|
||||
/// The maximum size of the upload request. Default value is just below CloudFlare's max request size.
|
||||
let bugReportMaxUploadSize = 50 * 1024 * 1024
|
||||
|
||||
@@ -257,9 +254,6 @@ final class AppSettings {
|
||||
// maptiler api key
|
||||
let mapTilerApiKey = InfoPlistReader.main.mapLibreAPIKey
|
||||
|
||||
// maptiler geocoding url
|
||||
let geocodingURLFormatString = "https://api.maptiler.com/geocoding/%f,%f.json"
|
||||
|
||||
// MARK: - Feature Flags
|
||||
|
||||
@UserPreference(key: UserDefaultsKeys.userSuggestionsEnabled, defaultValue: false, storageType: .volatile)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
// periphery:ignore - markdown protocol
|
||||
@MainActor
|
||||
protocol FlowCoordinatorProtocol {
|
||||
func handleAppRoute(_ appRoute: AppRoute, animated: Bool)
|
||||
|
||||
@@ -83,8 +83,6 @@ class AppLockFlowCoordinator: CoordinatorProtocol {
|
||||
|
||||
private let stateMachine: StateMachine<State, Event>
|
||||
|
||||
/// A task used to await biometric unlock before showing the PIN screen.
|
||||
@CancellableTask private var unlockTask: Task<Void, Never>?
|
||||
private var cancellables: Set<AnyCancellable> = []
|
||||
|
||||
/// Whether or not biometric unlock should be attempted instead of asking for a PIN.
|
||||
|
||||
@@ -39,7 +39,6 @@ internal enum Asset {
|
||||
internal static let addLocation = ImageAsset(name: "images/add-location")
|
||||
internal static let attachment = ImageAsset(name: "images/attachment")
|
||||
internal static let takePhoto = ImageAsset(name: "images/take-photo")
|
||||
internal static let textFormatting = ImageAsset(name: "images/text-formatting")
|
||||
internal static let bold = ImageAsset(name: "images/bold")
|
||||
internal static let bulletList = ImageAsset(name: "images/bullet-list")
|
||||
internal static let closeRte = ImageAsset(name: "images/close-rte")
|
||||
|
||||
@@ -45,18 +45,6 @@ extension ApplicationMock {
|
||||
underlyingApplicationState = applicationState
|
||||
underlyingBackgroundTimeRemaining = backgroundTimeRemaining
|
||||
|
||||
beginBackgroundTaskExpirationHandlerClosure = { [weak self] handler in
|
||||
guard let self else {
|
||||
return .invalid
|
||||
}
|
||||
|
||||
guard allowTasks else {
|
||||
return .invalid
|
||||
}
|
||||
|
||||
return beginBackgroundTask(withName: nil, expirationHandler: handler)
|
||||
}
|
||||
|
||||
beginBackgroundTaskWithNameExpirationHandlerClosure = { _, handler in
|
||||
guard allowTasks else {
|
||||
return .invalid
|
||||
|
||||
@@ -56,18 +56,6 @@ class AnalyticsClientMock: AnalyticsClientProtocol {
|
||||
stopCallsCount += 1
|
||||
stopClosure?()
|
||||
}
|
||||
//MARK: - flush
|
||||
|
||||
var flushCallsCount = 0
|
||||
var flushCalled: Bool {
|
||||
return flushCallsCount > 0
|
||||
}
|
||||
var flushClosure: (() -> Void)?
|
||||
|
||||
func flush() {
|
||||
flushCallsCount += 1
|
||||
flushClosure?()
|
||||
}
|
||||
//MARK: - capture
|
||||
|
||||
var captureCallsCount = 0
|
||||
@@ -100,22 +88,6 @@ class AnalyticsClientMock: AnalyticsClientProtocol {
|
||||
screenReceivedInvocations.append(event)
|
||||
screenClosure?(event)
|
||||
}
|
||||
//MARK: - updateUserProperties
|
||||
|
||||
var updateUserPropertiesCallsCount = 0
|
||||
var updateUserPropertiesCalled: Bool {
|
||||
return updateUserPropertiesCallsCount > 0
|
||||
}
|
||||
var updateUserPropertiesReceivedUserProperties: AnalyticsEvent.UserProperties?
|
||||
var updateUserPropertiesReceivedInvocations: [AnalyticsEvent.UserProperties] = []
|
||||
var updateUserPropertiesClosure: ((AnalyticsEvent.UserProperties) -> Void)?
|
||||
|
||||
func updateUserProperties(_ userProperties: AnalyticsEvent.UserProperties) {
|
||||
updateUserPropertiesCallsCount += 1
|
||||
updateUserPropertiesReceivedUserProperties = userProperties
|
||||
updateUserPropertiesReceivedInvocations.append(userProperties)
|
||||
updateUserPropertiesClosure?(userProperties)
|
||||
}
|
||||
}
|
||||
class AppLockServiceMock: AppLockServiceProtocol {
|
||||
var isMandatory: Bool {
|
||||
@@ -323,23 +295,6 @@ class ApplicationMock: ApplicationProtocol {
|
||||
|
||||
//MARK: - beginBackgroundTask
|
||||
|
||||
var beginBackgroundTaskExpirationHandlerCallsCount = 0
|
||||
var beginBackgroundTaskExpirationHandlerCalled: Bool {
|
||||
return beginBackgroundTaskExpirationHandlerCallsCount > 0
|
||||
}
|
||||
var beginBackgroundTaskExpirationHandlerReturnValue: UIBackgroundTaskIdentifier!
|
||||
var beginBackgroundTaskExpirationHandlerClosure: (((() -> Void)?) -> UIBackgroundTaskIdentifier)?
|
||||
|
||||
func beginBackgroundTask(expirationHandler handler: (() -> Void)?) -> UIBackgroundTaskIdentifier {
|
||||
beginBackgroundTaskExpirationHandlerCallsCount += 1
|
||||
if let beginBackgroundTaskExpirationHandlerClosure = beginBackgroundTaskExpirationHandlerClosure {
|
||||
return beginBackgroundTaskExpirationHandlerClosure(handler)
|
||||
} else {
|
||||
return beginBackgroundTaskExpirationHandlerReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - beginBackgroundTask
|
||||
|
||||
var beginBackgroundTaskWithNameExpirationHandlerCallsCount = 0
|
||||
var beginBackgroundTaskWithNameExpirationHandlerCalled: Bool {
|
||||
return beginBackgroundTaskWithNameExpirationHandlerCallsCount > 0
|
||||
@@ -739,18 +694,6 @@ class BugReportServiceMock: BugReportServiceProtocol {
|
||||
resetCallsCount += 1
|
||||
resetClosure?()
|
||||
}
|
||||
//MARK: - crash
|
||||
|
||||
var crashCallsCount = 0
|
||||
var crashCalled: Bool {
|
||||
return crashCallsCount > 0
|
||||
}
|
||||
var crashClosure: (() -> Void)?
|
||||
|
||||
func crash() {
|
||||
crashCallsCount += 1
|
||||
crashClosure?()
|
||||
}
|
||||
//MARK: - submitBugReport
|
||||
|
||||
var submitBugReportProgressListenerCallsCount = 0
|
||||
|
||||
@@ -106,10 +106,6 @@ enum RoomAvatarSizeOnScreen {
|
||||
}
|
||||
|
||||
extension AvatarSize {
|
||||
var size: CGSize {
|
||||
CGSize(width: value, height: value)
|
||||
}
|
||||
|
||||
var scaledSize: CGSize {
|
||||
CGSize(width: scaledValue, height: scaledValue)
|
||||
}
|
||||
|
||||
@@ -130,12 +130,6 @@ private extension String {
|
||||
self[index(startIndex, offsetBy: offset)]
|
||||
}
|
||||
|
||||
subscript(bounds: CountableClosedRange<Int>) -> Substring {
|
||||
let start = index(startIndex, offsetBy: bounds.lowerBound)
|
||||
let end = index(startIndex, offsetBy: bounds.upperBound)
|
||||
return self[start...end]
|
||||
}
|
||||
|
||||
subscript(bounds: CountableRange<Int>) -> Substring {
|
||||
let start = index(startIndex, offsetBy: bounds.lowerBound)
|
||||
let end = index(startIndex, offsetBy: bounds.upperBound)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
// periphery:ignore - property wrappers generate false positives
|
||||
@propertyWrapper
|
||||
struct CancellableTask<S: Sendable, F: Error> {
|
||||
private var storedValue: Task<S, F>?
|
||||
|
||||
@@ -47,18 +47,18 @@ struct CollapsibleReactionLayout: Layout {
|
||||
rows: collapsedRows,
|
||||
collapseButton: subviewsByType.collapseButton,
|
||||
addMoreButton: subviewsByType.addMoreButton)
|
||||
let size = sizeThatFits(proposal: proposal, rows: collapsedRowsWithButtons)
|
||||
let size = sizeThatFits(rows: collapsedRowsWithButtons)
|
||||
return size
|
||||
} else {
|
||||
// Show all subviews with the button at the end
|
||||
var rowsWithButtons = calculateRows(proposal: proposal, subviews: Array(subviews))
|
||||
ensureCollapseAndAddMoreButtonsAreOnTheSameRow(&rowsWithButtons)
|
||||
let size = sizeThatFits(proposal: proposal, rows: rowsWithButtons)
|
||||
let size = sizeThatFits(rows: rowsWithButtons)
|
||||
return size
|
||||
}
|
||||
} else {
|
||||
// Otherwise we are just calculating the size of all items without the button
|
||||
return sizeThatFits(proposal: proposal, rows: reactionsAndAddMore)
|
||||
return sizeThatFits(rows: reactionsAndAddMore)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ struct CollapsibleReactionLayout: Layout {
|
||||
/// - proposal: The proposed size
|
||||
/// - rows: The list of rows
|
||||
/// - Returns: The size render the rows
|
||||
private func sizeThatFits(proposal: ProposedViewSize, rows: [[FlowLayoutSubview]]) -> CGSize {
|
||||
private func sizeThatFits(rows: [[FlowLayoutSubview]]) -> CGSize {
|
||||
let sizes = rows.map { row in
|
||||
row.map { subview in
|
||||
subview.sizeThatFits(.unspecified)
|
||||
|
||||
@@ -31,6 +31,18 @@ extension View {
|
||||
})
|
||||
return alert(item.wrappedValue?.title ?? "", isPresented: binding, presenting: item.wrappedValue, actions: actions, message: message)
|
||||
}
|
||||
|
||||
// periphery: ignore - not used yet but might be useful
|
||||
func alert<Item, Actions>(item: Binding<Item?>, @ViewBuilder actions: (Item) -> Actions) -> some View where Item: AlertProtocol, Actions: View {
|
||||
let binding = Binding<Bool>(get: {
|
||||
item.wrappedValue != nil
|
||||
}, set: { newValue in
|
||||
if !newValue {
|
||||
item.wrappedValue = nil
|
||||
}
|
||||
})
|
||||
return alert(item.wrappedValue?.title ?? "", isPresented: binding, presenting: item.wrappedValue, actions: actions)
|
||||
}
|
||||
}
|
||||
|
||||
/// A type that describes an alert to be shown to the user.
|
||||
|
||||
@@ -73,13 +73,3 @@ extension Array where Element == RoomTimelineItemProtocol {
|
||||
first { $0.id.timelineID == id.timelineID }
|
||||
}
|
||||
}
|
||||
|
||||
extension Array {
|
||||
func appending(_ element: Element) -> [Element] {
|
||||
self + [element]
|
||||
}
|
||||
|
||||
func appending(_ elements: [Element]) -> [Element] {
|
||||
self + elements
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ extension View {
|
||||
return confirmationDialog(item.wrappedValue?.title ?? "", isPresented: binding, titleVisibility: titleVisibility, presenting: item.wrappedValue, actions: actions)
|
||||
}
|
||||
|
||||
// periphery: ignore - not used yet but might be useful
|
||||
func confirmationDialog<Item, Actions, Message>(item: Binding<Item?>,
|
||||
titleVisibility: Visibility = .automatic,
|
||||
@ViewBuilder actions: (Item) -> Actions,
|
||||
|
||||
@@ -21,9 +21,3 @@ extension MapTilerStyleBuilder {
|
||||
self.init(baseURL: appSettings.mapTilerBaseURL, key: appSettings.mapTilerApiKey)
|
||||
}
|
||||
}
|
||||
|
||||
extension MapTilerGeoCodingService {
|
||||
init(session: URLSession = .shared, appSettings: AppSettings) {
|
||||
self.init(session: session, key: appSettings.mapTilerApiKey, geocodingURL: appSettings.geocodingURLFormatString)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
||||
private let cacheKey: String
|
||||
private let temporaryBlockquoteMarkingColor = UIColor.magenta
|
||||
private let temporaryCodeBlockMarkingColor = UIColor.cyan
|
||||
private let linkColor = UIColor.blue
|
||||
private let permalinkBaseURL: URL
|
||||
private let mentionBuilder: MentionBuilderProtocol
|
||||
|
||||
@@ -33,10 +32,6 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
||||
caches.removeAll()
|
||||
}
|
||||
|
||||
static func invalidateCache(for key: String = defaultKey) {
|
||||
caches[key]?.removeAllValues()
|
||||
}
|
||||
|
||||
init(cacheKey: String = defaultKey, permalinkBaseURL: URL, mentionBuilder: MentionBuilderProtocol) {
|
||||
self.cacheKey = cacheKey
|
||||
if Self.caches[cacheKey] == nil {
|
||||
@@ -73,7 +68,7 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
||||
// that could happen with the default HTML renderer of NSAttributedString which is a
|
||||
// webview.
|
||||
func fromHTML(_ htmlString: String?) -> AttributedString? {
|
||||
guard var originalHTMLString = htmlString else {
|
||||
guard let originalHTMLString = htmlString else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -18,27 +18,27 @@ import Foundation
|
||||
|
||||
enum BlockquoteAttribute: AttributedStringKey {
|
||||
typealias Value = Bool
|
||||
public static var name = "MXBlockquoteAttribute"
|
||||
static var name = "MXBlockquoteAttribute"
|
||||
}
|
||||
|
||||
enum UserIDAttribute: AttributedStringKey {
|
||||
typealias Value = String
|
||||
public static var name = "MXUserIDAttribute"
|
||||
static var name = "MXUserIDAttribute"
|
||||
}
|
||||
|
||||
enum RoomIDAttribute: AttributedStringKey {
|
||||
typealias Value = String
|
||||
public static var name = "MXRoomIDAttribute"
|
||||
static var name = "MXRoomIDAttribute"
|
||||
}
|
||||
|
||||
enum RoomAliasAttribute: AttributedStringKey {
|
||||
typealias Value = String
|
||||
public static var name = "MXRoomAliasAttribute"
|
||||
static var name = "MXRoomAliasAttribute"
|
||||
}
|
||||
|
||||
enum AllUsersMentionAttribute: AttributedStringKey {
|
||||
typealias Value = Bool
|
||||
public static var name = "MXAllUsersMentionAttribute"
|
||||
static var name = "MXAllUsersMentionAttribute"
|
||||
}
|
||||
|
||||
struct EventIDAttributeValue: Hashable {
|
||||
@@ -48,9 +48,10 @@ struct EventIDAttributeValue: Hashable {
|
||||
|
||||
enum EventIDAttribute: AttributedStringKey {
|
||||
typealias Value = EventIDAttributeValue
|
||||
public static var name = "MXEventIDAttribute"
|
||||
static var name = "MXEventIDAttribute"
|
||||
}
|
||||
|
||||
// periphery: ignore - required to make NSAttributedString to AttributedString conversion even if not used directly
|
||||
extension AttributeScopes {
|
||||
struct ElementXAttributes: AttributeScope {
|
||||
let blockquote: BlockquoteAttribute
|
||||
@@ -69,6 +70,7 @@ extension AttributeScopes {
|
||||
var elementX: ElementXAttributes.Type { ElementXAttributes.self }
|
||||
}
|
||||
|
||||
// periphery: ignore - required to make NSAttributedString to AttributedString conversion even if not used directly
|
||||
extension AttributeDynamicLookup {
|
||||
subscript<T: AttributedStringKey>(dynamicMember keyPath: KeyPath<AttributeScopes.ElementXAttributes, T>) -> T {
|
||||
self[T.self]
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
//
|
||||
// Copyright 2023 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 CoreLocation
|
||||
import Foundation
|
||||
|
||||
struct MapTilerGeoCodingService: MapTilerGeoCodingServiceProtocol {
|
||||
private let key: String
|
||||
private let session: URLSession
|
||||
private let geocodingURL: String
|
||||
|
||||
init(session: URLSession = .shared, key: String, geocodingURL: String) {
|
||||
self.session = session
|
||||
self.key = key
|
||||
self.geocodingURL = geocodingURL
|
||||
}
|
||||
|
||||
private struct GeocodedPlace: Decodable {
|
||||
struct FeatureCollection: Decodable {
|
||||
let placeName: String
|
||||
}
|
||||
|
||||
let features: [FeatureCollection]
|
||||
}
|
||||
|
||||
func reverseGeoCoding(for coordinate: CLLocationCoordinate2D) async -> Result<String, MapTilerGeocodingError> {
|
||||
let latitude = coordinate.latitude
|
||||
let longitude = coordinate.longitude
|
||||
|
||||
let path = String(format: geocodingURL, longitude, latitude)
|
||||
guard var url = URL(string: path) else { return .failure(.wrongGeocodingURL) }
|
||||
let authorization = MapTilerAuthorization(key: key)
|
||||
url = authorization.authorizeURL(url)
|
||||
url.append(queryItems: [.init(name: "limit", value: "1")])
|
||||
|
||||
var request = URLRequest(url: url)
|
||||
request.httpMethod = "GET"
|
||||
|
||||
do {
|
||||
let (data, response) = try await session.dataWithRetry(for: request)
|
||||
|
||||
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
|
||||
let errorDescription = String(data: data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "Unknown"
|
||||
MXLog.error("Failed to get reverse geocoding: \(errorDescription)")
|
||||
MXLog.error("Response: \(response)")
|
||||
return .failure(.geocodingFailed)
|
||||
}
|
||||
|
||||
// Parse the JSON data
|
||||
let decoder = JSONDecoder()
|
||||
decoder.keyDecodingStrategy = .convertFromSnakeCase
|
||||
let decodedResponse = try decoder.decode(GeocodedPlace.self, from: data)
|
||||
guard let placeName = decodedResponse.features.first?.placeName else { return .failure(.geocodingFailed) }
|
||||
return .success(placeName)
|
||||
} catch {
|
||||
return .failure(.geocodingFailed)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,6 @@ public extension Animation {
|
||||
/// - Parameters:
|
||||
/// - animation: Animation
|
||||
/// - body: operations to be animated
|
||||
public func withElementAnimation<Result>(_ animation: Animation? = .default, _ body: () throws -> Result) rethrows -> Result {
|
||||
func withElementAnimation<Result>(_ animation: Animation? = .default, _ body: () throws -> Result) rethrows -> Result {
|
||||
try withAnimation(animation?.disabledDuringTests(), body)
|
||||
}
|
||||
|
||||
@@ -79,11 +79,8 @@ struct ShimmerOverlay_Previews: PreviewProvider, TestablePreview {
|
||||
static let viewModel = HomeScreenViewModel(userSession: MockUserSession(clientProxy: MockClientProxy(userID: ""),
|
||||
mediaProvider: MockMediaProvider(),
|
||||
voiceMessageMediaManager: VoiceMessageMediaManagerMock()),
|
||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
|
||||
mentionBuilder: MentionBuilder()),
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
analytics: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
|
||||
static var previews: some View {
|
||||
|
||||
@@ -27,7 +27,11 @@ struct CustomLayoutLabelStyle: LabelStyle {
|
||||
let spacing: CGFloat
|
||||
var alignment: VerticalAlignment
|
||||
|
||||
enum IconLayout { case leading, trailing }
|
||||
enum IconLayout {
|
||||
case leading
|
||||
case trailing
|
||||
}
|
||||
|
||||
var iconLayout: IconLayout
|
||||
|
||||
fileprivate init(spacing: CGFloat, alignment: VerticalAlignment, iconLayout: IconLayout) {
|
||||
@@ -38,10 +42,11 @@ struct CustomLayoutLabelStyle: LabelStyle {
|
||||
|
||||
func makeBody(configuration: Configuration) -> some View {
|
||||
HStack(alignment: alignment, spacing: spacing) {
|
||||
if iconLayout == .leading {
|
||||
switch iconLayout {
|
||||
case .leading:
|
||||
configuration.icon
|
||||
configuration.title
|
||||
} else {
|
||||
case .trailing:
|
||||
configuration.title
|
||||
configuration.icon
|
||||
}
|
||||
|
||||
@@ -26,11 +26,11 @@ struct AppActivityView: UIViewControllerRepresentable {
|
||||
private var onCancel: (() -> Void)?
|
||||
private var onComplete: CompletionType?
|
||||
|
||||
public init(activityItems: [Any],
|
||||
applicationActivities: [UIActivity]? = nil,
|
||||
excludedActivityTypes: [UIActivity.ActivityType] = [],
|
||||
onCancel: (() -> Void)? = nil,
|
||||
onComplete: CompletionType? = nil) {
|
||||
init(activityItems: [Any],
|
||||
applicationActivities: [UIActivity]? = nil,
|
||||
excludedActivityTypes: [UIActivity.ActivityType] = [],
|
||||
onCancel: (() -> Void)? = nil,
|
||||
onComplete: CompletionType? = nil) {
|
||||
self.activityItems = activityItems
|
||||
self.applicationActivities = applicationActivities
|
||||
self.excludedActivityTypes = excludedActivityTypes
|
||||
@@ -38,7 +38,7 @@ struct AppActivityView: UIViewControllerRepresentable {
|
||||
self.onComplete = onComplete
|
||||
}
|
||||
|
||||
public func makeUIViewController(context: Context) -> UIViewControllerType {
|
||||
func makeUIViewController(context: Context) -> UIViewControllerType {
|
||||
let viewController = UIViewControllerType(activityItems: activityItems, applicationActivities: applicationActivities)
|
||||
viewController.excludedActivityTypes = excludedActivityTypes
|
||||
|
||||
@@ -57,9 +57,9 @@ struct AppActivityView: UIViewControllerRepresentable {
|
||||
return viewController
|
||||
}
|
||||
|
||||
public func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) { }
|
||||
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) { }
|
||||
|
||||
public static func dismantleUIViewController(_ uiViewController: UIViewControllerType, coordinator: Coordinator) {
|
||||
static func dismantleUIViewController(_ uiViewController: UIViewControllerType, coordinator: Coordinator) {
|
||||
uiViewController.completionWithItemsHandler = nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
//
|
||||
// Copyright 2022 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 SwiftUI
|
||||
|
||||
/// A toggle style that uses a button, with a checked/unchecked image like a checkbox.
|
||||
struct ElementToggleStyle: ToggleStyle {
|
||||
func makeBody(configuration: Configuration) -> some View {
|
||||
Button { configuration.isOn.toggle() } label: {
|
||||
Image(systemName: configuration.isOn ? "checkmark.square.fill" : "square")
|
||||
.font(.title3.weight(.regular))
|
||||
.imageScale(.large)
|
||||
.foregroundColor(.compound.textActionPrimary)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,6 @@ struct EstimatedWaveformView: View {
|
||||
var lineWidth: CGFloat = 2
|
||||
var linePadding: CGFloat = 2
|
||||
var waveform: EstimatedWaveform
|
||||
private let minimumGraphAmplitude: CGFloat = 1
|
||||
var progress: CGFloat = 0.0
|
||||
|
||||
@State private var normalizedWaveformData: [Float] = []
|
||||
|
||||
@@ -30,7 +30,6 @@ enum AppLockScreenCoordinatorAction {
|
||||
}
|
||||
|
||||
final class AppLockScreenCoordinator: CoordinatorProtocol {
|
||||
private let parameters: AppLockScreenCoordinatorParameters
|
||||
private var viewModel: AppLockScreenViewModelProtocol
|
||||
private let actionsSubject: PassthroughSubject<AppLockScreenCoordinatorAction, Never> = .init()
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
@@ -40,8 +39,6 @@ final class AppLockScreenCoordinator: CoordinatorProtocol {
|
||||
}
|
||||
|
||||
init(parameters: AppLockScreenCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
|
||||
viewModel = AppLockScreenViewModel(appLockService: parameters.appLockService)
|
||||
}
|
||||
|
||||
|
||||
-3
@@ -26,7 +26,6 @@ enum AppLockSetupBiometricsScreenCoordinatorAction {
|
||||
}
|
||||
|
||||
final class AppLockSetupBiometricsScreenCoordinator: CoordinatorProtocol {
|
||||
private let parameters: AppLockSetupBiometricsScreenCoordinatorParameters
|
||||
private var viewModel: AppLockSetupBiometricsScreenViewModelProtocol
|
||||
private let actionsSubject: PassthroughSubject<AppLockSetupBiometricsScreenCoordinatorAction, Never> = .init()
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
@@ -36,8 +35,6 @@ final class AppLockSetupBiometricsScreenCoordinator: CoordinatorProtocol {
|
||||
}
|
||||
|
||||
init(parameters: AppLockSetupBiometricsScreenCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
|
||||
viewModel = AppLockSetupBiometricsScreenViewModel(appLockService: parameters.appLockService)
|
||||
}
|
||||
|
||||
|
||||
-2
@@ -36,7 +36,6 @@ enum AppLockSetupPINScreenCoordinatorAction {
|
||||
}
|
||||
|
||||
final class AppLockSetupPINScreenCoordinator: CoordinatorProtocol {
|
||||
private let parameters: AppLockSetupPINScreenCoordinatorParameters
|
||||
private var viewModel: AppLockSetupPINScreenViewModelProtocol
|
||||
private let actionsSubject: PassthroughSubject<AppLockSetupPINScreenCoordinatorAction, Never> = .init()
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
@@ -48,7 +47,6 @@ final class AppLockSetupPINScreenCoordinator: CoordinatorProtocol {
|
||||
init(parameters: AppLockSetupPINScreenCoordinatorParameters) {
|
||||
guard parameters.initialMode != .confirm else { fatalError(".confirm is an invalid initial mode") }
|
||||
|
||||
self.parameters = parameters
|
||||
viewModel = AppLockSetupPINScreenViewModel(initialMode: parameters.initialMode,
|
||||
isMandatory: parameters.isMandatory,
|
||||
appLockService: parameters.appLockService)
|
||||
|
||||
+2
-2
@@ -45,7 +45,7 @@ class AppLockSetupPINScreenViewModel: AppLockSetupPINScreenViewModelType, AppLoc
|
||||
.debounce(for: 0.1, scheduler: DispatchQueue.main) // Show the last digit for long enough to be read.
|
||||
.sink { [weak self] pinCode in
|
||||
guard pinCode.count == 4 else { return }
|
||||
self?.submit(pinCode)
|
||||
self?.submit()
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
@@ -64,7 +64,7 @@ class AppLockSetupPINScreenViewModel: AppLockSetupPINScreenViewModelType, AppLoc
|
||||
// MARK: - Private
|
||||
|
||||
/// Handle the entered PIN code.
|
||||
private func submit(_ pinCode: String) {
|
||||
private func submit() {
|
||||
switch state.mode {
|
||||
case .create:
|
||||
createPIN()
|
||||
|
||||
-3
@@ -29,7 +29,6 @@ enum AppLockSetupSettingsScreenCoordinatorAction {
|
||||
}
|
||||
|
||||
final class AppLockSetupSettingsScreenCoordinator: CoordinatorProtocol {
|
||||
private let parameters: AppLockSetupSettingsScreenCoordinatorParameters
|
||||
private var viewModel: AppLockSetupSettingsScreenViewModelProtocol
|
||||
private let actionsSubject: PassthroughSubject<AppLockSetupSettingsScreenCoordinatorAction, Never> = .init()
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
@@ -39,8 +38,6 @@ final class AppLockSetupSettingsScreenCoordinator: CoordinatorProtocol {
|
||||
}
|
||||
|
||||
init(parameters: AppLockSetupSettingsScreenCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
|
||||
viewModel = AppLockSetupSettingsScreenViewModel(appLockService: parameters.appLockService)
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,7 @@ import SwiftUI
|
||||
|
||||
@MainActor
|
||||
protocol AuthenticationCoordinatorDelegate: AnyObject {
|
||||
func authenticationCoordinator(_ authenticationCoordinator: AuthenticationCoordinator,
|
||||
didLoginWithSession userSession: UserSessionProtocol)
|
||||
func authenticationCoordinator(didLoginWithSession userSession: UserSessionProtocol)
|
||||
}
|
||||
|
||||
class AuthenticationCoordinator: CoordinatorProtocol {
|
||||
@@ -34,6 +33,7 @@ class AuthenticationCoordinator: CoordinatorProtocol {
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
private var oidcPresenter: OIDCAuthenticationPresenter?
|
||||
// periphery: ignore - used to store the coordinator to avoid deallocation
|
||||
private var appLockFlowCoordinator: AppLockSetupFlowCoordinator?
|
||||
|
||||
weak var delegate: AuthenticationCoordinatorDelegate?
|
||||
@@ -245,7 +245,7 @@ class AuthenticationCoordinator: CoordinatorProtocol {
|
||||
} else if analytics.shouldShowAnalyticsPrompt {
|
||||
showAnalyticsPrompt(userSession: userSession)
|
||||
} else {
|
||||
delegate?.authenticationCoordinator(self, didLoginWithSession: userSession)
|
||||
delegate?.authenticationCoordinator(didLoginWithSession: userSession)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,7 +261,7 @@ class AuthenticationCoordinator: CoordinatorProtocol {
|
||||
if analytics.shouldShowAnalyticsPrompt {
|
||||
showAnalyticsPrompt(userSession: userSession)
|
||||
} else {
|
||||
delegate?.authenticationCoordinator(self, didLoginWithSession: userSession)
|
||||
delegate?.authenticationCoordinator(didLoginWithSession: userSession)
|
||||
}
|
||||
case .forceLogout:
|
||||
fatalError("The PIN creation flow should not fail.")
|
||||
@@ -281,7 +281,7 @@ class AuthenticationCoordinator: CoordinatorProtocol {
|
||||
guard let self else { return }
|
||||
switch action {
|
||||
case .done:
|
||||
delegate?.authenticationCoordinator(self, didLoginWithSession: userSession)
|
||||
delegate?.authenticationCoordinator(didLoginWithSession: userSession)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
@@ -44,7 +44,6 @@ public extension TextFieldStyle where Self == AuthenticationTextFieldStyle {
|
||||
/// The text field style used in authentication screens.
|
||||
public struct AuthenticationTextFieldStyle: TextFieldStyle {
|
||||
@Environment(\.isEnabled) private var isEnabled
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
|
||||
@FocusState private var isFocused: Bool
|
||||
public let labelText: Text?
|
||||
|
||||
@@ -24,6 +24,7 @@ class BugReportScreenViewModel: BugReportScreenViewModelType, BugReportScreenVie
|
||||
private let userID: String
|
||||
private let deviceID: String?
|
||||
private let actionsSubject: PassthroughSubject<BugReportScreenViewModelAction, Never> = .init()
|
||||
// periphery:ignore - when set to nil this is automatically cancelled
|
||||
@CancellableTask private var uploadTask: Task<Void, Never>?
|
||||
|
||||
var actions: AnyPublisher<BugReportScreenViewModelAction, Never> {
|
||||
|
||||
@@ -140,12 +140,6 @@ struct BugReportScreen: View {
|
||||
// MARK: - Previews
|
||||
|
||||
struct BugReport_Previews: PreviewProvider, TestablePreview {
|
||||
static let viewModel = BugReportScreenViewModel(bugReportService: BugReportServiceMock(),
|
||||
userID: "@mock.client.com",
|
||||
deviceID: nil,
|
||||
screenshot: nil,
|
||||
isModallyPresented: false)
|
||||
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
BugReportScreen(context: BugReportScreenViewModel(bugReportService: BugReportServiceMock(),
|
||||
|
||||
@@ -32,7 +32,6 @@ enum CallScreenCoordinatorAction {
|
||||
}
|
||||
|
||||
final class CallScreenCoordinator: CoordinatorProtocol {
|
||||
private let parameters: CallScreenCoordinatorParameters
|
||||
private var viewModel: CallScreenViewModelProtocol
|
||||
private let actionsSubject: PassthroughSubject<CallScreenCoordinatorAction, Never> = .init()
|
||||
|
||||
@@ -42,8 +41,6 @@ final class CallScreenCoordinator: CoordinatorProtocol {
|
||||
}
|
||||
|
||||
init(parameters: CallScreenCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
|
||||
viewModel = CallScreenViewModel(roomProxy: parameters.roomProxy,
|
||||
callBaseURL: parameters.callBaseURL,
|
||||
clientID: parameters.clientID,
|
||||
|
||||
@@ -23,13 +23,13 @@ typealias CallScreenViewModelType = StateStoreViewModel<CallScreenViewState, Cal
|
||||
|
||||
class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol {
|
||||
private let roomProxy: RoomProxyProtocol
|
||||
private let callBaseURL: URL
|
||||
private let clientID: String
|
||||
|
||||
private let widgetDriver: ElementCallWidgetDriverProtocol
|
||||
|
||||
private let callController = CXCallController()
|
||||
// periphery: ignore - call kit magic do not remove
|
||||
private let callProvider = CXProvider(configuration: .init())
|
||||
|
||||
private let callID = UUID()
|
||||
|
||||
private let actionsSubject: PassthroughSubject<CallScreenViewModelAction, Never> = .init()
|
||||
@@ -51,8 +51,6 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
|
||||
clientID: String,
|
||||
useEncryption: Bool) {
|
||||
self.roomProxy = roomProxy
|
||||
self.callBaseURL = callBaseURL
|
||||
self.clientID = clientID
|
||||
|
||||
widgetDriver = roomProxy.elementCallWidgetDriver()
|
||||
|
||||
@@ -132,12 +130,14 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
|
||||
|
||||
// MARK: - CXCallObserverDelegate
|
||||
|
||||
// periphery: ignore - call kit magic do not remove
|
||||
func callObserver(_ callObserver: CXCallObserver, callChanged call: CXCall) {
|
||||
MXLog.info("Call changed: \(call)")
|
||||
}
|
||||
|
||||
// MARK: - CXProviderDelegate
|
||||
|
||||
// periphery: ignore - call kit magic do not remove
|
||||
func providerDidReset(_ provider: CXProvider) {
|
||||
MXLog.info("Call provider did reset: \(provider)")
|
||||
}
|
||||
|
||||
@@ -53,7 +53,6 @@ private struct WebView: UIViewRepresentable {
|
||||
@MainActor
|
||||
class Coordinator: NSObject, WKScriptMessageHandler, WKUIDelegate, WKNavigationDelegate {
|
||||
private let viewModelContext: CallScreenViewModel.Context
|
||||
private var webViewURLObservation: NSKeyValueObservation?
|
||||
|
||||
private(set) var webView: WKWebView!
|
||||
|
||||
|
||||
@@ -30,15 +30,6 @@ enum SuggestionItem: Identifiable, Equatable {
|
||||
return PillConstants.atRoom
|
||||
}
|
||||
}
|
||||
|
||||
var name: String? {
|
||||
switch self {
|
||||
case .user(let user):
|
||||
return user.displayName
|
||||
case .allUsers:
|
||||
return PillConstants.everyone
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MentionSuggestionItem: Identifiable, Equatable {
|
||||
|
||||
@@ -25,6 +25,7 @@ struct SuggestionPattern: Equatable {
|
||||
let text: String
|
||||
}
|
||||
|
||||
// periphery: ignore - markdown protocol
|
||||
protocol ComposerToolbarViewModelProtocol {
|
||||
var actions: AnyPublisher<ComposerToolbarViewModelAction, Never> { get }
|
||||
var context: ComposerToolbarViewModelType.Context { get }
|
||||
|
||||
@@ -313,8 +313,8 @@ struct ComposerToolbar_Previews: PreviewProvider, TestablePreview {
|
||||
VStack(spacing: 8) {
|
||||
ComposerToolbar.textWithVoiceMessage(focused: false)
|
||||
ComposerToolbar.textWithVoiceMessage(focused: true)
|
||||
ComposerToolbar.voiceMessageRecordingMock(recording: true)
|
||||
ComposerToolbar.voiceMessagePreviewMock(recording: false, uploading: false)
|
||||
ComposerToolbar.voiceMessageRecordingMock()
|
||||
ComposerToolbar.voiceMessagePreviewMock(uploading: false)
|
||||
}
|
||||
.previewDisplayName("Voice Message")
|
||||
}
|
||||
@@ -355,7 +355,7 @@ extension ComposerToolbar {
|
||||
keyCommandHandler: { _ in false })
|
||||
}
|
||||
|
||||
static func voiceMessageRecordingMock(recording: Bool) -> ComposerToolbar {
|
||||
static func voiceMessageRecordingMock() -> ComposerToolbar {
|
||||
let wysiwygViewModel = WysiwygComposerViewModel()
|
||||
var composerViewModel: ComposerToolbarViewModel {
|
||||
let model = ComposerToolbarViewModel(wysiwygViewModel: wysiwygViewModel,
|
||||
@@ -371,7 +371,7 @@ extension ComposerToolbar {
|
||||
keyCommandHandler: { _ in false })
|
||||
}
|
||||
|
||||
static func voiceMessagePreviewMock(recording: Bool, uploading: Bool) -> ComposerToolbar {
|
||||
static func voiceMessagePreviewMock(uploading: Bool) -> ComposerToolbar {
|
||||
let wysiwygViewModel = WysiwygComposerViewModel()
|
||||
let waveformData: [Float] = Array(repeating: 1.0, count: 1000)
|
||||
var composerViewModel: ComposerToolbarViewModel {
|
||||
|
||||
@@ -33,7 +33,6 @@ enum CreateRoomCoordinatorAction {
|
||||
}
|
||||
|
||||
final class CreateRoomCoordinator: CoordinatorProtocol {
|
||||
private let parameters: CreateRoomCoordinatorParameters
|
||||
private var viewModel: CreateRoomViewModelProtocol
|
||||
private let actionsSubject: PassthroughSubject<CreateRoomCoordinatorAction, Never> = .init()
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
@@ -43,7 +42,6 @@ final class CreateRoomCoordinator: CoordinatorProtocol {
|
||||
}
|
||||
|
||||
init(parameters: CreateRoomCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
viewModel = CreateRoomViewModel(userSession: parameters.userSession,
|
||||
createRoomParameters: parameters.createRoomParameters,
|
||||
selectedUsers: parameters.selectedUsers,
|
||||
|
||||
@@ -39,7 +39,6 @@ enum HomeScreenCoordinatorAction {
|
||||
}
|
||||
|
||||
final class HomeScreenCoordinator: CoordinatorProtocol {
|
||||
private let parameters: HomeScreenCoordinatorParameters
|
||||
private var viewModel: HomeScreenViewModelProtocol
|
||||
|
||||
private let actionsSubject: PassthroughSubject<HomeScreenCoordinatorAction, Never> = .init()
|
||||
@@ -50,13 +49,9 @@ final class HomeScreenCoordinator: CoordinatorProtocol {
|
||||
}
|
||||
|
||||
init(parameters: HomeScreenCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
|
||||
viewModel = HomeScreenViewModel(userSession: parameters.userSession,
|
||||
attributedStringBuilder: parameters.attributedStringBuilder,
|
||||
selectedRoomPublisher: parameters.selectedRoomPublisher,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
analytics: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
|
||||
viewModel.actions
|
||||
|
||||
@@ -21,9 +21,7 @@ typealias HomeScreenViewModelType = StateStoreViewModel<HomeScreenViewState, Hom
|
||||
|
||||
class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol {
|
||||
private let userSession: UserSessionProtocol
|
||||
private let attributedStringBuilder: AttributedStringBuilderProtocol
|
||||
private let appSettings: AppSettings
|
||||
private let analytics: AnalyticsService
|
||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||
|
||||
private let roomSummaryProvider: RoomSummaryProviderProtocol?
|
||||
@@ -39,15 +37,11 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
}
|
||||
|
||||
init(userSession: UserSessionProtocol,
|
||||
attributedStringBuilder: AttributedStringBuilderProtocol,
|
||||
selectedRoomPublisher: CurrentValuePublisher<String?, Never>,
|
||||
appSettings: AppSettings,
|
||||
analytics: AnalyticsService,
|
||||
userIndicatorController: UserIndicatorControllerProtocol) {
|
||||
self.userSession = userSession
|
||||
self.attributedStringBuilder = attributedStringBuilder
|
||||
self.appSettings = appSettings
|
||||
self.analytics = analytics
|
||||
self.userIndicatorController = userIndicatorController
|
||||
|
||||
roomSummaryProvider = userSession.clientProxy.roomSummaryProvider
|
||||
|
||||
@@ -306,14 +306,9 @@ struct HomeScreen_Previews: PreviewProvider, TestablePreview {
|
||||
mediaProvider: MockMediaProvider(),
|
||||
voiceMessageMediaManager: VoiceMessageMediaManagerMock())
|
||||
|
||||
let attributedStringBuilder = AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
|
||||
mentionBuilder: MentionBuilder())
|
||||
|
||||
return HomeScreenViewModel(userSession: userSession,
|
||||
attributedStringBuilder: attributedStringBuilder,
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
analytics: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,10 +155,8 @@ struct HomeScreenEmptyStateView_Previews: PreviewProvider, TestablePreview {
|
||||
voiceMessageMediaManager: VoiceMessageMediaManagerMock())
|
||||
|
||||
return HomeScreenViewModel(userSession: userSession,
|
||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL, mentionBuilder: MentionBuilder()),
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
analytics: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -72,14 +72,9 @@ struct HomeScreenRecoveryKeyConfirmationBanner_Previews: PreviewProvider, Testab
|
||||
mediaProvider: MockMediaProvider(),
|
||||
voiceMessageMediaManager: VoiceMessageMediaManagerMock())
|
||||
|
||||
let attributedStringBuilder = AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
|
||||
mentionBuilder: MentionBuilder())
|
||||
|
||||
return HomeScreenViewModel(userSession: userSession,
|
||||
attributedStringBuilder: attributedStringBuilder,
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
analytics: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,11 +186,8 @@ struct HomeScreenRoomCell_Previews: PreviewProvider, TestablePreview {
|
||||
voiceMessageMediaManager: VoiceMessageMediaManagerMock())
|
||||
|
||||
let viewModel = HomeScreenViewModel(userSession: userSession,
|
||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
|
||||
mentionBuilder: MentionBuilder()),
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
analytics: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
|
||||
let rooms: [HomeScreenRoom] = summaryProvider.roomListPublisher.value.compactMap { summary -> HomeScreenRoom? in
|
||||
|
||||
@@ -72,14 +72,9 @@ struct HomeScreenSessionVerificationBanner_Previews: PreviewProvider, TestablePr
|
||||
mediaProvider: MockMediaProvider(),
|
||||
voiceMessageMediaManager: VoiceMessageMediaManagerMock())
|
||||
|
||||
let attributedStringBuilder = AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
|
||||
mentionBuilder: MentionBuilder())
|
||||
|
||||
return HomeScreenViewModel(userSession: userSession,
|
||||
attributedStringBuilder: attributedStringBuilder,
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
analytics: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@ import Compound
|
||||
import SwiftUI
|
||||
|
||||
struct HomeScreenUserMenuButton: View {
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
|
||||
@ObservedObject var context: HomeScreenViewModel.Context
|
||||
|
||||
var body: some View {
|
||||
|
||||
@@ -518,7 +518,7 @@ class RoomScreenInteractionHandler {
|
||||
}
|
||||
} catch {
|
||||
MXLog.error("Failed to load voice message: \(error)")
|
||||
audioPlayerState.reportError(error)
|
||||
audioPlayerState.reportError()
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
+1
@@ -14,6 +14,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
// periphery: ignore - markdown protocol
|
||||
protocol TextBasedRoomTimelineViewProtocol {
|
||||
associatedtype TimelineItemType: TextBasedRoomTimelineItem
|
||||
|
||||
|
||||
-2
@@ -20,11 +20,9 @@ import SwiftUI
|
||||
typealias AnalyticsSettingsScreenViewModelType = StateStoreViewModel<AnalyticsSettingsScreenViewState, AnalyticsSettingsScreenViewAction>
|
||||
|
||||
class AnalyticsSettingsScreenViewModel: AnalyticsSettingsScreenViewModelType, AnalyticsSettingsScreenViewModelProtocol {
|
||||
private let appSettings: AppSettings
|
||||
private let analytics: AnalyticsService
|
||||
|
||||
init(appSettings: AppSettings, analytics: AnalyticsService) {
|
||||
self.appSettings = appSettings
|
||||
self.analytics = analytics
|
||||
|
||||
let strings = AnalyticsSettingsScreenStrings(termsURL: appSettings.analyticsConfiguration.termsURL)
|
||||
|
||||
+1
@@ -14,6 +14,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
// periphery:ignore:all - subscripts lead to false positives
|
||||
import Foundation
|
||||
|
||||
struct AdvancedSettingsScreenViewState: BindableState {
|
||||
|
||||
+1
@@ -24,6 +24,7 @@ struct DeveloperOptionsScreenViewState: BindableState {
|
||||
var bindings: DeveloperOptionsScreenViewStateBindings
|
||||
}
|
||||
|
||||
// periphery: ignore - subscripts are seen as false positive
|
||||
@dynamicMemberLookup
|
||||
struct DeveloperOptionsScreenViewStateBindings {
|
||||
private let developerOptions: DeveloperOptionsProtocol
|
||||
|
||||
@@ -31,9 +31,6 @@ protocol AnalyticsClientProtocol {
|
||||
/// Stop the analytics client reporting data.
|
||||
func stop()
|
||||
|
||||
/// Send any queued events immediately.
|
||||
func flush()
|
||||
|
||||
/// Capture the supplied analytics event.
|
||||
/// - Parameter event: The event to capture.
|
||||
func capture(_ event: AnalyticsEventProtocol)
|
||||
@@ -41,14 +38,6 @@ protocol AnalyticsClientProtocol {
|
||||
/// Capture the supplied analytics screen event.
|
||||
/// - Parameter event: The screen event to capture.
|
||||
func screen(_ event: AnalyticsScreenProtocol)
|
||||
|
||||
/// Updates any user properties to help with creating cohorts.
|
||||
/// - Parameter userProperties: The user properties to be updated.
|
||||
///
|
||||
/// Only non-nil properties will be updated when calling this method. There might
|
||||
/// be a delay when updating user properties as these are cached to be included
|
||||
/// as part of the next event that gets captured.
|
||||
func updateUserProperties(_ userProperties: AnalyticsEvent.UserProperties)
|
||||
}
|
||||
|
||||
// sourcery: AutoMockable
|
||||
|
||||
@@ -105,13 +105,6 @@ class AnalyticsService {
|
||||
appSettings.analyticsConsentState = .unknown
|
||||
}
|
||||
|
||||
/// Flushes the event queue in the analytics client, uploading all pending events.
|
||||
/// Normally events are sent in batches. Call this method when you need an event
|
||||
/// to be sent immediately.
|
||||
func forceUpload() {
|
||||
client.flush()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
/// Capture an event in the `client`.
|
||||
|
||||
@@ -24,10 +24,6 @@ protocol AudioSessionProtocol: AnyObject {
|
||||
}
|
||||
|
||||
extension AudioSessionProtocol {
|
||||
func setCategory(_ category: AVAudioSession.Category, mode: AVAudioSession.Mode) throws {
|
||||
try setCategory(category, mode: mode, options: [])
|
||||
}
|
||||
|
||||
func setActive(_ active: Bool) throws {
|
||||
try setActive(active, options: [])
|
||||
}
|
||||
|
||||
@@ -46,12 +46,13 @@ class AudioPlayer: NSObject, AudioPlayerProtocol {
|
||||
|
||||
private var statusObserver: NSKeyValueObservation?
|
||||
private var rateObserver: NSKeyValueObservation?
|
||||
private var playToEndObserver: NSObjectProtocol?
|
||||
private var appBackgroundObserver: NSObjectProtocol?
|
||||
private var autoplay = false
|
||||
|
||||
private let audioSession = AVAudioSession.sharedInstance()
|
||||
|
||||
// periphery:ignore - when set to nil is automatically cancelled
|
||||
@CancellableTask private var releaseAudioSessionTask: Task<Void, Never>?
|
||||
|
||||
private let releaseAudioSessionTimeoutInterval = 5.0
|
||||
|
||||
private(set) var url: URL?
|
||||
|
||||
@@ -19,7 +19,6 @@ import Foundation
|
||||
|
||||
enum AudioPlayerError: Error {
|
||||
case genericError
|
||||
case loadFileError
|
||||
}
|
||||
|
||||
enum AudioPlayerAction {
|
||||
|
||||
@@ -110,7 +110,7 @@ class AudioPlayerState: ObservableObject, Identifiable {
|
||||
playbackState = .stopped
|
||||
}
|
||||
|
||||
func reportError(_ error: Error) {
|
||||
func reportError() {
|
||||
playbackState = .error
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@ class AudioPlayerState: ObservableObject, Identifiable {
|
||||
displayLink?.add(to: .current, forMode: .common)
|
||||
}
|
||||
|
||||
// periphery:ignore:parameters displayLink - required for objc selector
|
||||
@objc private func updateProgress(displayLink: CADisplayLink) {
|
||||
if let currentTime = audioPlayer?.currentTime, duration > 0 {
|
||||
progress = currentTime / duration
|
||||
|
||||
@@ -343,9 +343,9 @@ class AudioRecorder: AudioRecorderProtocol {
|
||||
.store(in: &cancellables)
|
||||
|
||||
NotificationCenter.default.publisher(for: Notification.Name.AVAudioEngineConfigurationChange)
|
||||
.sink { [weak self] notification in
|
||||
.sink { [weak self] _ in
|
||||
guard let self else { return }
|
||||
self.handleConfigurationChange(notification: notification)
|
||||
self.handleConfigurationChange()
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
@@ -396,7 +396,7 @@ class AudioRecorder: AudioRecorderProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
func handleConfigurationChange(notification: Notification) {
|
||||
func handleConfigurationChange() {
|
||||
guard let audioEngine else { return }
|
||||
MXLog.warning("Configuration changed: \(audioEngine.inputNode.inputFormat(forBus: 0))")
|
||||
if internalState != .suspended {
|
||||
|
||||
@@ -24,7 +24,6 @@ enum AudioRecorderError: Error, Equatable {
|
||||
case audioFileCreationFailure
|
||||
case interrupted
|
||||
case recordingCancelled
|
||||
case recordingFailed
|
||||
case recordPermissionNotGranted
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ class AudioRecorderState: ObservableObject, Identifiable {
|
||||
recordingState = .stopped
|
||||
}
|
||||
|
||||
func reportError(_ error: Error) {
|
||||
func reportError() {
|
||||
recordingState = .error
|
||||
}
|
||||
|
||||
@@ -98,6 +98,7 @@ class AudioRecorderState: ObservableObject, Identifiable {
|
||||
displayLink?.add(to: .current, forMode: .common)
|
||||
}
|
||||
|
||||
// periphery:ignore:parameters displayLink - required for objc selector
|
||||
@objc private func publishUpdate(displayLink: CADisplayLink) {
|
||||
if let currentTime = audioRecorder?.currentTime {
|
||||
duration = currentTime
|
||||
|
||||
@@ -19,8 +19,6 @@ import UIKit
|
||||
|
||||
// sourcery: AutoMockable
|
||||
protocol ApplicationProtocol {
|
||||
func beginBackgroundTask(expirationHandler handler: (() -> Void)?) -> UIBackgroundTaskIdentifier
|
||||
|
||||
func beginBackgroundTask(withName taskName: String?, expirationHandler handler: (() -> Void)?) -> UIBackgroundTaskIdentifier
|
||||
|
||||
func endBackgroundTask(_ identifier: UIBackgroundTaskIdentifier)
|
||||
|
||||
@@ -29,12 +29,6 @@ protocol BackgroundTaskProtocol: AnyObject {
|
||||
/// Flag indicating the background task is reusable. If reusable, `name` is the key to distinguish background tasks.
|
||||
var isReusable: Bool { get }
|
||||
|
||||
/// Elapsed time after the task started. In milliseconds.
|
||||
var elapsedTime: TimeInterval { get }
|
||||
|
||||
/// Expiration handler for the background task
|
||||
var expirationHandler: BackgroundTaskExpirationHandler? { get }
|
||||
|
||||
/// Method to be called when a task reused one more time. Should only be valid for reusable tasks.
|
||||
func reuse()
|
||||
|
||||
|
||||
@@ -115,10 +115,6 @@ class BugReportService: NSObject, BugReportServiceProtocol {
|
||||
lastCrashEventId = nil
|
||||
MXLog.info("Reset.")
|
||||
}
|
||||
|
||||
func crash() {
|
||||
SentrySDK.crash()
|
||||
}
|
||||
|
||||
func submitBugReport(_ bugReport: BugReport,
|
||||
progressListener: CurrentValueSubject<Double, Never>) async -> Result<SubmitBugReportResponse, BugReportServiceError> {
|
||||
|
||||
@@ -52,6 +52,7 @@ enum BugReportServiceError: LocalizedError {
|
||||
|
||||
// sourcery: AutoMockable
|
||||
protocol BugReportServiceProtocol {
|
||||
// periphery: ignore
|
||||
var isRunning: Bool { get }
|
||||
|
||||
var crashedLastRun: Bool { get }
|
||||
@@ -61,8 +62,6 @@ protocol BugReportServiceProtocol {
|
||||
func stop()
|
||||
|
||||
func reset()
|
||||
|
||||
func crash()
|
||||
|
||||
func submitBugReport(_ bugReport: BugReport,
|
||||
progressListener: CurrentValueSubject<Double, Never>) async -> Result<SubmitBugReportResponse, BugReportServiceError>
|
||||
|
||||
@@ -25,15 +25,17 @@ class ClientProxy: ClientProxyProtocol {
|
||||
private let appSettings: AppSettings
|
||||
private let networkMonitor: NetworkMonitorProtocol
|
||||
|
||||
private var sessionVerificationControllerProxy: SessionVerificationControllerProxy?
|
||||
private let mediaLoader: MediaLoaderProtocol
|
||||
private let clientQueue: DispatchQueue
|
||||
|
||||
private var roomListService: RoomListService?
|
||||
// periphery: ignore - only for retain
|
||||
private var roomListStateUpdateTaskHandle: TaskHandle?
|
||||
// periphery: ignore - only for retain
|
||||
private var roomListStateLoadingStateUpdateTaskHandle: TaskHandle?
|
||||
|
||||
private var syncService: SyncService?
|
||||
// periphery: ignore - only for retain
|
||||
private var syncServiceStateUpdateTaskHandle: TaskHandle?
|
||||
|
||||
private var delegateHandle: TaskHandle?
|
||||
@@ -48,8 +50,6 @@ class ClientProxy: ClientProxyProtocol {
|
||||
let notificationSettings: NotificationSettingsProxyProtocol
|
||||
|
||||
let secureBackupController: SecureBackupControllerProtocol
|
||||
|
||||
private let roomListRecencyOrderingAllowedEventTypes = ["m.room.message", "m.room.encrypted", "m.sticker"]
|
||||
|
||||
private static var roomCreationPowerLevelOverrides: PowerLevels {
|
||||
.init(usersDefault: nil,
|
||||
@@ -79,7 +79,6 @@ class ClientProxy: ClientProxyProtocol {
|
||||
}
|
||||
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
private var visibleRoomsListProxyStateObservationToken: AnyCancellable?
|
||||
|
||||
/// Will be `true` whilst the app cleans up and forces a logout. Prevents the sync service from restarting
|
||||
/// before the client is released which ends up running in a loop. This is a workaround until the sync service
|
||||
@@ -413,18 +412,6 @@ class ClientProxy: ClientProxyProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
func accountDataEvent<Content>(type: String) async -> Result<Content?, ClientProxyError> where Content: Decodable {
|
||||
await Task.dispatch(on: clientQueue) {
|
||||
.failure(.failedRetrievingAccountData)
|
||||
}
|
||||
}
|
||||
|
||||
func setAccountData<Content: Encodable>(content: Content, type: String) async -> Result<Void, ClientProxyError> {
|
||||
await Task.dispatch(on: clientQueue) {
|
||||
.failure(.failedSettingAccountData)
|
||||
}
|
||||
}
|
||||
|
||||
func sessionVerificationControllerProxy() async -> Result<SessionVerificationControllerProxyProtocol, ClientProxyError> {
|
||||
await Task.dispatch(on: clientQueue) {
|
||||
do {
|
||||
|
||||
@@ -42,8 +42,6 @@ enum ClientProxyError: Error {
|
||||
case failedRetrievingUserDisplayName
|
||||
case failedRetrievingUserAvatarURL
|
||||
case failedSettingUserDisplayName
|
||||
case failedRetrievingAccountData
|
||||
case failedSettingAccountData
|
||||
case failedRetrievingSessionVerificationController
|
||||
case failedLoadingMedia
|
||||
case mediaFileError
|
||||
@@ -122,11 +120,7 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol {
|
||||
func setUserAvatar(media: MediaInfo) async -> Result<Void, ClientProxyError>
|
||||
|
||||
func removeUserAvatar() async -> Result<Void, ClientProxyError>
|
||||
|
||||
func accountDataEvent<Content: Decodable>(type: String) async -> Result<Content?, ClientProxyError>
|
||||
|
||||
func setAccountData<Content: Encodable>(content: Content, type: String) async -> Result<Void, ClientProxyError>
|
||||
|
||||
|
||||
func sessionVerificationControllerProxy() async -> Result<SessionVerificationControllerProxyProtocol, ClientProxyError>
|
||||
|
||||
func logout() async -> URL?
|
||||
|
||||
@@ -117,14 +117,6 @@ class MockClientProxy: ClientProxyProtocol {
|
||||
.failure(.failedSettingUserAvatar)
|
||||
}
|
||||
|
||||
func accountDataEvent<Content>(type: String) async -> Result<Content?, ClientProxyError> where Content: Decodable {
|
||||
.failure(.failedRetrievingAccountData)
|
||||
}
|
||||
|
||||
func setAccountData<Content>(content: Content, type: String) async -> Result<Void, ClientProxyError> where Content: Encodable {
|
||||
.failure(.failedSettingAccountData)
|
||||
}
|
||||
|
||||
func loadMediaContentForSource(_ source: MediaSourceProxy) async throws -> Data {
|
||||
throw ClientProxyError.failedLoadingMedia
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ enum ElementCallWidgetDriverError: Error {
|
||||
|
||||
enum ElementCallWidgetDriverAction {
|
||||
case callEnded
|
||||
case errorReceived(ElementCallWidgetDriverError)
|
||||
}
|
||||
|
||||
// sourcery: AutoMockable
|
||||
|
||||
@@ -25,5 +25,4 @@ struct EmojiItem: Equatable, Identifiable {
|
||||
let unicode: String
|
||||
let keywords: [String]
|
||||
let shortcodes: [String]
|
||||
let skins: [String]
|
||||
}
|
||||
|
||||
@@ -97,6 +97,5 @@ extension EmojiItem {
|
||||
label = emojibase.label
|
||||
shortcodes = emojibase.shortcodes
|
||||
keywords = emojibase.tags ?? []
|
||||
skins = emojibase.skins?.map(\.unicode) ?? []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@ extension NotificationManager: UNUserNotificationCenterDelegate {
|
||||
return [.badge, .sound, .list, .banner]
|
||||
}
|
||||
|
||||
guard delegate.shouldDisplayInAppNotification(self, content: notification.request.content) else {
|
||||
guard delegate.shouldDisplayInAppNotification(content: notification.request.content) else {
|
||||
return []
|
||||
}
|
||||
|
||||
@@ -245,8 +245,7 @@ extension NotificationManager: UNUserNotificationCenterDelegate {
|
||||
content: response.notification.request.content,
|
||||
replyText: response.userText)
|
||||
case UNNotificationDefaultActionIdentifier:
|
||||
await delegate?.notificationTapped(self,
|
||||
content: response.notification.request.content)
|
||||
await delegate?.notificationTapped(content: response.notification.request.content)
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
@@ -18,10 +18,8 @@ import Foundation
|
||||
import UserNotifications
|
||||
|
||||
protocol NotificationManagerDelegate: AnyObject {
|
||||
func shouldDisplayInAppNotification(_ service: NotificationManagerProtocol,
|
||||
content: UNNotificationContent) -> Bool
|
||||
func notificationTapped(_ service: NotificationManagerProtocol,
|
||||
content: UNNotificationContent) async
|
||||
func shouldDisplayInAppNotification(content: UNNotificationContent) -> Bool
|
||||
func notificationTapped(content: UNNotificationContent) async
|
||||
func handleInlineReply(_ service: NotificationManagerProtocol,
|
||||
content: UNNotificationContent,
|
||||
replyText: String) async
|
||||
|
||||
@@ -16,4 +16,5 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
// periphery: ignore - markdown protocol
|
||||
protocol DecorationTimelineItemProtocol: RoomTimelineItemProtocol { }
|
||||
|
||||
Reference in New Issue
Block a user