diff --git a/Config/BuildSettings.swift b/Config/BuildSettings.swift index 7998caf91..00e6138e5 100644 --- a/Config/BuildSettings.swift +++ b/Config/BuildSettings.swift @@ -369,4 +369,12 @@ final class BuildSettings: NSObject { // MARK: - Location Sharing static let tileServerMapURL = URL(string: "https://api.maptiler.com/maps/streets/style.json?key=" + RiotKeys().mapTilerAPIKey)! + + static var locationSharingEnabled: Bool { + guard #available(iOS 14, *) else { + return false + } + + return false + } } diff --git a/Riot/Managers/Settings/RiotSettings.swift b/Riot/Managers/Settings/RiotSettings.swift index b99421751..1813d8818 100644 --- a/Riot/Managers/Settings/RiotSettings.swift +++ b/Riot/Managers/Settings/RiotSettings.swift @@ -188,7 +188,7 @@ final class RiotSettings: NSObject { @UserDefault(key: "roomScreenAllowPollsAction", defaultValue: false, storage: defaults) var roomScreenAllowPollsAction - @UserDefault(key: "roomScreenAllowLocationAction", defaultValue: true, storage: defaults) + @UserDefault(key: "roomScreenAllowLocationAction", defaultValue: false, storage: defaults) var roomScreenAllowLocationAction @UserDefault(key: "roomScreenShowsURLPreviews", defaultValue: true, storage: defaults) diff --git a/Riot/Modules/Room/Views/BubbleCells/Location/LocationBubbleCell.swift b/Riot/Modules/Room/Views/BubbleCells/Location/LocationBubbleCell.swift index befca8096..c7628ae13 100644 --- a/Riot/Modules/Room/Views/BubbleCells/Location/LocationBubbleCell.swift +++ b/Riot/Modules/Room/Views/BubbleCells/Location/LocationBubbleCell.swift @@ -50,7 +50,8 @@ class LocationBubbleCell: SizableBaseBubbleCell, BubbleCellReactionsDisplayable bubbleCellContentView?.showSenderInfo = true bubbleCellContentView?.showPaginationTitle = false - guard let contentView = bubbleCellContentView?.innerContentView else { + guard #available(iOS 14.0, *), + let contentView = bubbleCellContentView?.innerContentView else { return } diff --git a/Riot/Modules/Settings/SettingsViewController.m b/Riot/Modules/Settings/SettingsViewController.m index aed8be3be..2970c51f7 100644 --- a/Riot/Modules/Settings/SettingsViewController.m +++ b/Riot/Modules/Settings/SettingsViewController.m @@ -381,10 +381,13 @@ TableViewSectionsDelegate> sectionUserSettings.headerTitle = [VectorL10n settingsUserSettings]; [tmpSections addObject:sectionUserSettings]; - Section *sectionLocationSharing = [Section sectionWithTag:SECTION_TAG_LOCATION_SHARING]; - [sectionLocationSharing addRowWithTag:LOCATION_SHARING_ENABLED]; - sectionLocationSharing.headerTitle = VectorL10n.locationSharingSettingsHeader.uppercaseString; - [tmpSections addObject:sectionLocationSharing]; + if (BuildSettings.locationSharingEnabled) + { + Section *sectionLocationSharing = [Section sectionWithTag:SECTION_TAG_LOCATION_SHARING]; + [sectionLocationSharing addRowWithTag:LOCATION_SHARING_ENABLED]; + sectionLocationSharing.headerTitle = VectorL10n.locationSharingSettingsHeader.uppercaseString; + [tmpSections addObject:sectionLocationSharing]; + } if (BuildSettings.settingsScreenShowConfirmMediaSize) { diff --git a/RiotSwiftUI/Modules/AnalyticsPrompt/Test/UI/AnalyticsPromptUITests.swift b/RiotSwiftUI/Modules/AnalyticsPrompt/Test/UI/AnalyticsPromptUITests.swift index ada017da6..b8a38a117 100644 --- a/RiotSwiftUI/Modules/AnalyticsPrompt/Test/UI/AnalyticsPromptUITests.swift +++ b/RiotSwiftUI/Modules/AnalyticsPrompt/Test/UI/AnalyticsPromptUITests.swift @@ -49,7 +49,7 @@ class AnalyticsPromptUITests: MockScreenTest { switch promptType { case .newUser: XCTAssertEqual(enableButton.label, VectorL10n.enable) - XCTAssertEqual(disableButton.label, VectorL10n.cancel) + XCTAssertEqual(disableButton.label, VectorL10n.locationSharingInvalidAuthorizationNotNow) case .upgrade: XCTAssertEqual(enableButton.label, VectorL10n.analyticsPromptYes) XCTAssertEqual(disableButton.label, VectorL10n.analyticsPromptStop) diff --git a/RiotSwiftUI/Modules/Room/LocationSharing/LocationSharingModels.swift b/RiotSwiftUI/Modules/Room/LocationSharing/LocationSharingModels.swift index cdb8b6203..be9c188f9 100644 --- a/RiotSwiftUI/Modules/Room/LocationSharing/LocationSharingModels.swift +++ b/RiotSwiftUI/Modules/Room/LocationSharing/LocationSharingModels.swift @@ -53,7 +53,7 @@ struct LocationSharingViewState: BindableState { var showLoadingIndicator: Bool = false var shareButtonVisible: Bool { - (location == nil) + return location == nil } var shareButtonEnabled: Bool { diff --git a/RiotSwiftUI/Modules/Room/LocationSharing/LocationSharingScreenState.swift b/RiotSwiftUI/Modules/Room/LocationSharing/LocationSharingScreenState.swift index 01c77b09d..f316d761e 100644 --- a/RiotSwiftUI/Modules/Room/LocationSharing/LocationSharingScreenState.swift +++ b/RiotSwiftUI/Modules/Room/LocationSharing/LocationSharingScreenState.swift @@ -17,19 +17,28 @@ import Foundation import SwiftUI import Keys +import CoreLocation @available(iOS 14.0, *) enum MockLocationSharingScreenState: MockScreenState, CaseIterable { - case standard + case shareUserLocation + case displayExistingLocation var screenType: Any.Type { MockLocationSharingScreenState.self } var screenView: ([Any], AnyView) { + + var location: CLLocationCoordinate2D? + if self == .displayExistingLocation { + location = CLLocationCoordinate2D(latitude: 51.4932641, longitude: -0.257096) + } + let mapURL = URL(string: "https://api.maptiler.com/maps/streets/style.json?key=" + RiotKeys().mapTilerAPIKey)! let viewModel = LocationSharingViewModel(tileServerMapURL: mapURL, - avatarData: AvatarInput(mxContentUri: "", matrixItemId: "", displayName: "Alice")) + avatarData: AvatarInput(mxContentUri: "", matrixItemId: "", displayName: "Alice"), + location: location) return ([viewModel], AnyView(LocationSharingView(context: viewModel.context) .addDependency(MockAvatarService.example))) diff --git a/RiotSwiftUI/Modules/Room/LocationSharing/Test/UI/LocationSharingUITests.swift b/RiotSwiftUI/Modules/Room/LocationSharing/Test/UI/LocationSharingUITests.swift index 36838557d..6e68f3556 100644 --- a/RiotSwiftUI/Modules/Room/LocationSharing/Test/UI/LocationSharingUITests.swift +++ b/RiotSwiftUI/Modules/Room/LocationSharing/Test/UI/LocationSharingUITests.swift @@ -24,13 +24,30 @@ class LocationSharingUITests: XCTestCase { override func setUp() { continueAfterFailure = false - + app = XCUIApplication() app.launch() - app.buttons[MockLocationSharingScreenState.screenStateKeys.first!].tap() } - func testInitialStateComponents() { + func testInitialUserLocation() { + goToScreenWithIdentifier(MockLocationSharingScreenState.shareUserLocation.title) + XCTAssertTrue(app.buttons["Cancel"].exists) + XCTAssertTrue(app.buttons["Share"].exists) + XCTAssertTrue(app.otherElements["Map"].exists) + } + + func testInitialExistingLocation() { + goToScreenWithIdentifier(MockLocationSharingScreenState.displayExistingLocation.title) + + XCTAssertTrue(app.buttons["Cancel"].exists) + XCTAssertTrue(app.buttons["location share icon"].exists) + XCTAssertTrue(app.otherElements["Map"].exists) + } + + // Need a delay when showing the map otherwise the simulator breaks + private func goToScreenWithIdentifier(_ identifier: String) { + app.goToScreenWithIdentifier(identifier) + sleep(2) } } diff --git a/RiotSwiftUI/Modules/Room/LocationSharing/Test/Unit/LocationSharingViewModelTests.swift b/RiotSwiftUI/Modules/Room/LocationSharing/Test/Unit/LocationSharingViewModelTests.swift index dc51dd83e..e3371727c 100644 --- a/RiotSwiftUI/Modules/Room/LocationSharing/Test/Unit/LocationSharingViewModelTests.swift +++ b/RiotSwiftUI/Modules/Room/LocationSharing/Test/Unit/LocationSharingViewModelTests.swift @@ -16,20 +16,113 @@ import XCTest import Combine +import CoreLocation @testable import RiotSwiftUI @available(iOS 14.0, *) class LocationSharingViewModelTests: XCTestCase { - var viewModel: LocationSharingViewModel! - var context: LocationSharingViewModelType.Context! + var cancellables = Set() - override func setUpWithError() throws { + func testInitialState() { + let viewModel = buildViewModel(withLocation: false) + XCTAssertTrue(viewModel.context.viewState.shareButtonEnabled) + XCTAssertTrue(viewModel.context.viewState.shareButtonVisible) + XCTAssertFalse(viewModel.context.viewState.showLoadingIndicator) + + XCTAssertNotNil(viewModel.context.viewState.tileServerMapURL) + XCTAssertNotNil(viewModel.context.viewState.avatarData) + + XCTAssertNil(viewModel.context.viewState.location) + XCTAssertNil(viewModel.context.viewState.bindings.userLocation) + XCTAssertNil(viewModel.context.viewState.bindings.alertInfo) } - func testInitialState() { - + func testCancellation() { + let viewModel = buildViewModel(withLocation: false) + + let expectation = self.expectation(description: "Cancellation completion should be invoked") + + viewModel.completion = { result in + switch result { + case .share: + XCTFail() + case .cancel: + expectation.fulfill() + } + } + + viewModel.context.send(viewAction: .cancel) + + waitForExpectations(timeout: 3) + } + + func testShareNoUserLocation() { + let viewModel = buildViewModel(withLocation: false) + + XCTAssertNil(viewModel.context.viewState.bindings.userLocation) + XCTAssertNil(viewModel.context.viewState.location) + + viewModel.context.send(viewAction: .share) + + XCTAssertNotNil(viewModel.context.viewState.bindings.alertInfo) + XCTAssertEqual(viewModel.context.viewState.bindings.alertInfo?.id, .userLocatingError) + } + + func testShareExistingLocation() { + let viewModel = buildViewModel(withLocation: true) + + let expectation = self.expectation(description: "Share completion should be invoked") + + viewModel.completion = { result in + switch result { + case .share(let latitude, let longitude): + XCTAssertEqual(latitude, viewModel.context.viewState.location?.latitude) + XCTAssertEqual(longitude, viewModel.context.viewState.location?.longitude) + expectation.fulfill() + case .cancel: + XCTFail() + } + } + + XCTAssertNil(viewModel.context.viewState.bindings.userLocation) + XCTAssertNotNil(viewModel.context.viewState.location) + + viewModel.context.send(viewAction: .share) + + XCTAssertNil(viewModel.context.viewState.bindings.alertInfo) + + waitForExpectations(timeout: 3) + } + + func testLoading() { + let viewModel = buildViewModel(withLocation: false) + + viewModel.dispatch(action: .startLoading) + + XCTAssertFalse(viewModel.context.viewState.shareButtonEnabled) + XCTAssertTrue(viewModel.context.viewState.showLoadingIndicator) + + viewModel.dispatch(action: .stopLoading(nil)) + + XCTAssertTrue(viewModel.context.viewState.shareButtonEnabled) + XCTAssertFalse(viewModel.context.viewState.showLoadingIndicator) + } + + func testInvalidLocationAuthorization() { + let viewModel = buildViewModel(withLocation: false) + + viewModel.context.viewState.errorSubject.send(.invalidLocationAuthorization) + + XCTAssertNotNil(viewModel.context.alertInfo) + XCTAssertEqual(viewModel.context.viewState.bindings.alertInfo?.id, .authorizationError) + } + + private func buildViewModel(withLocation: Bool) -> LocationSharingViewModel { + LocationSharingViewModel(tileServerMapURL: URL(string: "http://empty.com")!, + avatarData: AvatarInput(mxContentUri: "", matrixItemId: "", displayName: ""), + location: (withLocation ? CLLocationCoordinate2D(latitude: 51.4932641, longitude: -0.257096) : nil)) } }