mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 21:39:12 +00:00
Introduce primitives for working with fragment url query items; switch the generic call links to it.
This commit is contained in:
parent
56a9820ded
commit
a22bde91b2
@ -101,6 +101,7 @@
|
||||
1FEC0A4EC6E6DF693C16B32A /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CEBCB9676FCD1D0F13188DD /* StringTests.swift */; };
|
||||
206F0DBAB6AF042CA1FF2C0D /* SettingsViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D487C1185D658F8B15B8F55 /* SettingsViewModelTests.swift */; };
|
||||
208C19811613F9A10F8A7B75 /* MediaLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8AFCE895ECFFA53FEE64D62B /* MediaLoader.swift */; };
|
||||
20C16A3F718802B0E4A19C83 /* URLComponentsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76310030C831D4610A705603 /* URLComponentsTests.swift */; };
|
||||
2185C1F6724C78FFF355D6FA /* WelcomeScreenScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8AB10FA6570DD08B3966C159 /* WelcomeScreenScreenUITests.swift */; };
|
||||
21BF2B7CEDFE3CA67C5355AD /* test_image.png in Resources */ = {isa = PBXBuildFile; fileRef = C733D11B421CFE3A657EF230 /* test_image.png */; };
|
||||
22882C710BC99EC34A5024A0 /* UITestsScreenIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CEBE5EA91E8691EDF364EC2 /* UITestsScreenIdentifier.swift */; };
|
||||
@ -348,6 +349,7 @@
|
||||
6F2AB43A1EFAD8A97AF41A15 /* AnalyticsEvents in Frameworks */ = {isa = PBXBuildFile; productRef = 2A3F7BCCB18C15B30CCA39A9 /* AnalyticsEvents */; };
|
||||
6F2D5D4F2590310DFAE973E4 /* WaitingDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6D698BFD68B061350553930 /* WaitingDialog.swift */; };
|
||||
6FC10A00D268FCD48B631E37 /* ViewFrameReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFF7BF82A950B91BC5469E91 /* ViewFrameReader.swift */; };
|
||||
6FD8053301C5FEFA82D2F246 /* URLComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BFDCA5A09EE70BC17F2EFA7 /* URLComponents.swift */; };
|
||||
6FF51EB400DBA0668FC38B97 /* TimelineStartRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9ED8E731E21055F728E5FED /* TimelineStartRoomTimelineView.swift */; };
|
||||
70394ECD2DCC70741538620D /* AccessibilityIdentifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04BB8DDE245ED86C489BA983 /* AccessibilityIdentifiers.swift */; };
|
||||
70558528EF68CAAEF09972D5 /* RoomTimelineItemFixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = E96ED747FF90332EA1333C22 /* RoomTimelineItemFixtures.swift */; };
|
||||
@ -1023,6 +1025,7 @@
|
||||
2AB2C848BB9A7A9B618B7B89 /* TextBasedRoomTimelineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBasedRoomTimelineTests.swift; sourceTree = "<group>"; };
|
||||
2AF715D4FD4710EBB637D661 /* SettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||
2BB385E148DE55C85C0A02D6 /* SoftLogoutScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoftLogoutScreenModels.swift; sourceTree = "<group>"; };
|
||||
2BFDCA5A09EE70BC17F2EFA7 /* URLComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLComponents.swift; sourceTree = "<group>"; };
|
||||
2C0197EAE9D45A662B8847B6 /* RoomTimelineControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineControllerProtocol.swift; sourceTree = "<group>"; };
|
||||
2CA028DCD4157F9A1F999827 /* BackgroundTaskProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundTaskProtocol.swift; sourceTree = "<group>"; };
|
||||
2CEBCB9676FCD1D0F13188DD /* StringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringTests.swift; sourceTree = "<group>"; };
|
||||
@ -1243,6 +1246,7 @@
|
||||
752A0EB49BF5BCEA37EDF7A3 /* Signposter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Signposter.swift; sourceTree = "<group>"; };
|
||||
75697AB5E64A12F1F069F511 /* EncryptedHistoryRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptedHistoryRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||
75910F5A36EA8FF9BAD08D18 /* MigrationScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationScreenUITests.swift; sourceTree = "<group>"; };
|
||||
76310030C831D4610A705603 /* URLComponentsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLComponentsTests.swift; sourceTree = "<group>"; };
|
||||
772334731A8BF8E6D90B194D /* LocationRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||
7773CBFDBD458E0B7E270507 /* PillView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillView.swift; sourceTree = "<group>"; };
|
||||
780258F1B9D15E30549FF4BE /* NotificationSettingsEditScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsEditScreenViewModel.swift; sourceTree = "<group>"; };
|
||||
@ -2323,6 +2327,7 @@
|
||||
287FC98AF2664EAD79C0D902 /* UIDevice.swift */,
|
||||
BE148A4FFEE853C5A281500C /* UNNotificationContent.swift */,
|
||||
227AC5D71A4CE43512062243 /* URL.swift */,
|
||||
2BFDCA5A09EE70BC17F2EFA7 /* URLComponents.swift */,
|
||||
AE40D4A5DD857AC16EED945A /* URLSession.swift */,
|
||||
897DF5E9A70CE05A632FC8AF /* UTType.swift */,
|
||||
E992D7B8BE54B2AB454613AF /* XCUIElement.swift */,
|
||||
@ -2747,6 +2752,7 @@
|
||||
2CEBCB9676FCD1D0F13188DD /* StringTests.swift */,
|
||||
2AB2C848BB9A7A9B618B7B89 /* TextBasedRoomTimelineTests.swift */,
|
||||
1734A445A58ED855B977A0A8 /* TracingConfigurationTests.swift */,
|
||||
76310030C831D4610A705603 /* URLComponentsTests.swift */,
|
||||
EB3B237387B8288A5A938F1B /* UserAgentBuilderTests.swift */,
|
||||
2429224EB0EEA34D35CE9249 /* UserIndicatorControllerTests.swift */,
|
||||
BA241DEEF7C8A7181C0AEDC9 /* UserPreferenceTests.swift */,
|
||||
@ -4535,6 +4541,7 @@
|
||||
282A5F3375DDC774AE09B0C3 /* TracingConfigurationTests.swift in Sources */,
|
||||
8E650379587C31D7912ED67B /* UNNotification+Creator.swift in Sources */,
|
||||
AF33B9044498211C3D82F1E1 /* UNTextInputNotificationResponse+Creator.swift in Sources */,
|
||||
20C16A3F718802B0E4A19C83 /* URLComponentsTests.swift in Sources */,
|
||||
8D3E1FADD78E72504DE0E402 /* UserAgentBuilderTests.swift in Sources */,
|
||||
E313BDD2B8813144139B2E00 /* UserDiscoveryServiceTest.swift in Sources */,
|
||||
A1DF0E1E526A981ED6D5DF44 /* UserIndicatorControllerTests.swift in Sources */,
|
||||
@ -5067,6 +5074,7 @@
|
||||
245F7FE5961BD10C145A26E0 /* UITimelineView.swift in Sources */,
|
||||
D02AA6208C7ACB9BE6332394 /* UNNotificationContent.swift in Sources */,
|
||||
071A017E415AD378F2961B11 /* URL.swift in Sources */,
|
||||
6FD8053301C5FEFA82D2F246 /* URLComponents.swift in Sources */,
|
||||
90733645AE76FB33DAD28C2B /* URLSession.swift in Sources */,
|
||||
18867F4F1C8991EEC56EA932 /* UTType.swift in Sources */,
|
||||
84226AD2E1F1FBC965F3B09E /* UnitTestsAppCoordinator.swift in Sources */,
|
||||
|
59
ElementX/Sources/Other/Extensions/URLComponents.swift
Normal file
59
ElementX/Sources/Other/Extensions/URLComponents.swift
Normal file
@ -0,0 +1,59 @@
|
||||
//
|
||||
// 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 Foundation
|
||||
|
||||
extension URLComponents {
|
||||
var fragmentQueryItems: [URLQueryItem]? {
|
||||
get {
|
||||
guard let fragment,
|
||||
let fragmentQuery = fragment.components(separatedBy: "?").last else {
|
||||
return nil
|
||||
}
|
||||
|
||||
var fragmentComponents = URLComponents()
|
||||
fragmentComponents.query = fragmentQuery
|
||||
|
||||
return fragmentComponents.queryItems
|
||||
}
|
||||
|
||||
set {
|
||||
var fragmentComponents = URLComponents()
|
||||
fragmentComponents.queryItems = newValue
|
||||
|
||||
guard let fragmentQuery = fragmentComponents.query else {
|
||||
MXLog.error("Failed building fragment query")
|
||||
return
|
||||
}
|
||||
|
||||
if let fragment, !fragment.isEmpty {
|
||||
var fragmentComponents = fragment.components(separatedBy: "?")
|
||||
|
||||
guard let firstFragmentComponent = fragmentComponents.first else {
|
||||
self.fragment = fragmentQuery
|
||||
return
|
||||
}
|
||||
|
||||
fragmentComponents = [firstFragmentComponent, fragmentQuery]
|
||||
|
||||
self.fragment = fragmentComponents.joined(separator: "?")
|
||||
|
||||
} else {
|
||||
fragment = "?" + fragmentQuery
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -54,21 +54,25 @@ private struct WebView: UIViewRepresentable {
|
||||
}
|
||||
|
||||
func updateUIView(_ webView: WKWebView, context: Context) {
|
||||
webView.load(URLRequest(url: url))
|
||||
webView.load(URLRequest(url: context.coordinator.url))
|
||||
}
|
||||
|
||||
@MainActor
|
||||
class Coordinator: NSObject, WKUIDelegate, WKNavigationDelegate {
|
||||
private let url: URL
|
||||
let url: URL
|
||||
private(set) var webView: WKWebView!
|
||||
|
||||
init(url: URL) {
|
||||
if var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: true) {
|
||||
urlComponents.queryItems?.removeAll { $0.name == GenericCallLinkQueryParameters.appPrompt }
|
||||
urlComponents.queryItems?.removeAll { $0.name == GenericCallLinkQueryParameters.confineToRoom }
|
||||
var fragmentQueryItems = urlComponents.fragmentQueryItems ?? []
|
||||
|
||||
urlComponents.queryItems?.append(.init(name: GenericCallLinkQueryParameters.appPrompt, value: "false"))
|
||||
urlComponents.queryItems?.append(.init(name: GenericCallLinkQueryParameters.confineToRoom, value: "true"))
|
||||
fragmentQueryItems.removeAll { $0.name == GenericCallLinkQueryParameters.appPrompt }
|
||||
fragmentQueryItems.removeAll { $0.name == GenericCallLinkQueryParameters.confineToRoom }
|
||||
|
||||
fragmentQueryItems.append(.init(name: GenericCallLinkQueryParameters.appPrompt, value: "false"))
|
||||
fragmentQueryItems.append(.init(name: GenericCallLinkQueryParameters.confineToRoom, value: "true"))
|
||||
|
||||
urlComponents.fragmentQueryItems = fragmentQueryItems
|
||||
|
||||
if let adjustedURL = urlComponents.url {
|
||||
self.url = adjustedURL
|
||||
|
111
UnitTests/Sources/URLComponentsTests.swift
Normal file
111
UnitTests/Sources/URLComponentsTests.swift
Normal file
@ -0,0 +1,111 @@
|
||||
//
|
||||
// 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 XCTest
|
||||
|
||||
@testable import ElementX
|
||||
|
||||
class URLComponentsTests: XCTestCase {
|
||||
func testAddFragmentQueryItems() {
|
||||
guard let url = URL(string: "https://test.matrix.org"),
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
XCTFail("URL invalid")
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssertNil(components.fragmentQueryItems)
|
||||
|
||||
let fragmentQueryItems: [URLQueryItem] = [.init(name: "first", value: "1"), .init(name: "second", value: "2")]
|
||||
components.fragmentQueryItems = fragmentQueryItems
|
||||
|
||||
XCTAssertEqual(components.url?.absoluteString, "https://test.matrix.org#?first=1&second=2")
|
||||
}
|
||||
|
||||
func testRemoveFragmentQueryItem() {
|
||||
guard let url = URL(string: "https://test.matrix.org#random/data?first=1&second=2"),
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
XCTFail("URL invalid")
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssertNotNil(components.fragmentQueryItems)
|
||||
guard var fragmentQueryItems = components.fragmentQueryItems else {
|
||||
return
|
||||
}
|
||||
|
||||
fragmentQueryItems.removeAll { $0.name == "first" }
|
||||
|
||||
components.fragmentQueryItems = fragmentQueryItems
|
||||
|
||||
XCTAssertEqual(components.url?.absoluteString, "https://test.matrix.org#random/data?second=2")
|
||||
}
|
||||
|
||||
func testAppendFragmentQueryItem() {
|
||||
guard let url = URL(string: "https://test.matrix.org#/random/data?first=1&second=2"),
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
XCTFail("URL invalid")
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssertNotNil(components.fragmentQueryItems)
|
||||
guard var fragmentQueryItems = components.fragmentQueryItems else {
|
||||
return
|
||||
}
|
||||
|
||||
fragmentQueryItems.insert(.init(name: "mr in between", value: "hello"), at: 1)
|
||||
|
||||
components.fragmentQueryItems = fragmentQueryItems
|
||||
|
||||
XCTAssertEqual(components.url?.absoluteString, "https://test.matrix.org#/random/data?first=1&mr%20in%20between=hello&second=2")
|
||||
}
|
||||
|
||||
func testChangeFragmentQueryItemValue() {
|
||||
guard let url = URL(string: "https://test.matrix.org#/random/data?first=1&second=2"),
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
XCTFail("URL invalid")
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssertNotNil(components.fragmentQueryItems)
|
||||
guard var fragmentQueryItems = components.fragmentQueryItems else {
|
||||
return
|
||||
}
|
||||
|
||||
fragmentQueryItems[0].value = "last"
|
||||
|
||||
components.fragmentQueryItems = fragmentQueryItems
|
||||
|
||||
XCTAssertEqual(components.url?.absoluteString, "https://test.matrix.org#/random/data?first=last&second=2")
|
||||
}
|
||||
|
||||
func testElementCallParameters() {
|
||||
guard let url = URL(string: "https://call.element.io/room#/callName?appPrompt=true&confineToRoom=false"),
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
XCTFail("URL invalid")
|
||||
return
|
||||
}
|
||||
|
||||
components.fragmentQueryItems?.removeAll { $0.name == "appPrompt" }
|
||||
components.fragmentQueryItems?.removeAll { $0.name == "confineToRoom" }
|
||||
|
||||
components.fragmentQueryItems?.append(.init(name: "skipLobby", value: "true"))
|
||||
|
||||
components.fragmentQueryItems?.append(.init(name: "appPrompt", value: "false"))
|
||||
components.fragmentQueryItems?.append(.init(name: "confineToRoom", value: "true"))
|
||||
|
||||
XCTAssertEqual(components.url?.absoluteString, "https://call.element.io/room#/callName?skipLobby=true&appPrompt=false&confineToRoom=true")
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user