diff --git a/WKRKit/WKRKit.xcodeproj/project.pbxproj b/WKRKit/WKRKit.xcodeproj/project.pbxproj index e8dcb57..7f20777 100644 --- a/WKRKit/WKRKit.xcodeproj/project.pbxproj +++ b/WKRKit/WKRKit.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 140CE30424C2967900ECA175 /* WKRLanguageHackery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140CE30324C2967900ECA175 /* WKRLanguageHackery.swift */; }; + 140CE30524C2967900ECA175 /* WKRLanguageHackery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140CE30324C2967900ECA175 /* WKRLanguageHackery.swift */; }; 140FCFC31F36547E00FFA84E /* WKRResultsInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140FCFC21F36547E00FFA84E /* WKRResultsInfo.swift */; }; 140FCFC51F36549900FFA84E /* WKRPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140FCFC41F36549900FFA84E /* WKRPlayer.swift */; }; 140FCFCB1F3654D500FFA84E /* WKRPlayerState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140FCFCA1F3654D500FFA84E /* WKRPlayerState.swift */; }; @@ -17,6 +19,9 @@ 141427FF21FBB84600C48788 /* WKRGameKitNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = 141427FE21FBB84600C48788 /* WKRGameKitNetwork.swift */; }; 142CB29A202EAC6B00BC6A33 /* WKRSoloNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = 142CB299202EAC6B00BC6A33 /* WKRSoloNetwork.swift */; }; 142CB29E202EC42000BC6A33 /* WKRPeerNetworkConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 142CB29D202EC42000BC6A33 /* WKRPeerNetworkConfig.swift */; }; + 144F33C024C34A24006E4437 /* WKRDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 144F33BF24C34A24006E4437 /* WKRDefaults.swift */; }; + 144F33C124C34A24006E4437 /* WKRDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 144F33BF24C34A24006E4437 /* WKRDefaults.swift */; }; + 144F33C224C34A24006E4437 /* WKRDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 144F33BF24C34A24006E4437 /* WKRDefaults.swift */; }; 1452B3721F36524400E81FD8 /* WKRPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1452B3711F36524400E81FD8 /* WKRPage.swift */; }; 1452B3741F36529300E81FD8 /* WKRKitConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1452B3731F36529300E81FD8 /* WKRKitConstants.swift */; }; 1452B3761F3652E900E81FD8 /* WKRRaceDurationConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1452B3751F3652E900E81FD8 /* WKRRaceDurationConstants.swift */; }; @@ -106,6 +111,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 140CE30324C2967900ECA175 /* WKRLanguageHackery.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKRLanguageHackery.swift; sourceTree = ""; }; 140FCFC21F36547E00FFA84E /* WKRResultsInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKRResultsInfo.swift; sourceTree = ""; }; 140FCFC41F36549900FFA84E /* WKRPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKRPlayer.swift; sourceTree = ""; }; 140FCFCA1F3654D500FFA84E /* WKRPlayerState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKRPlayerState.swift; sourceTree = ""; }; @@ -115,6 +121,7 @@ 141427FE21FBB84600C48788 /* WKRGameKitNetwork.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKRGameKitNetwork.swift; sourceTree = ""; }; 142CB299202EAC6B00BC6A33 /* WKRSoloNetwork.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKRSoloNetwork.swift; sourceTree = ""; }; 142CB29D202EC42000BC6A33 /* WKRPeerNetworkConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKRPeerNetworkConfig.swift; sourceTree = ""; }; + 144F33BF24C34A24006E4437 /* WKRDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKRDefaults.swift; sourceTree = ""; }; 1452B3711F36524400E81FD8 /* WKRPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKRPage.swift; sourceTree = ""; }; 1452B3731F36529300E81FD8 /* WKRKitConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKRKitConstants.swift; sourceTree = ""; }; 1452B3751F3652E900E81FD8 /* WKRRaceDurationConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKRRaceDurationConstants.swift; sourceTree = ""; }; @@ -320,6 +327,8 @@ 14EB9F651F36833A00FF1A9E /* WKROperation.swift */, 14B4DB86222674E2007D4B54 /* WKRLogEvent.swift */, 1499606D2226FCBF00259B68 /* WKRDurationFormatter.swift */, + 140CE30324C2967900ECA175 /* WKRLanguageHackery.swift */, + 144F33BF24C34A24006E4437 /* WKRDefaults.swift */, ); path = Other; sourceTree = ""; @@ -567,12 +576,14 @@ 146E054724AE3E9E001E1917 /* WKRPlayer.swift in Sources */, 146E054B24AE3EB2001E1917 /* WKRLinkedPagesFetcher.swift in Sources */, 146E054124AE3E95001E1917 /* WKRSeenFinalArticlesStore.swift in Sources */, + 140CE30524C2967900ECA175 /* WKRLanguageHackery.swift in Sources */, 146E053F24AE3E95001E1917 /* WKRHistoryEntry.swift in Sources */, 146E054224AE3E95001E1917 /* WKRPage.swift in Sources */, 146E053024AE3E80001E1917 /* WKRRaceDurationConstants.swift in Sources */, 146E053B24AE3E8F001E1917 /* WKRDurationFormatter.swift in Sources */, 146E053C24AE3E8F001E1917 /* WKRKit+Array.swift in Sources */, 146E053924AE3E85001E1917 /* WKRRaceSettings.swift in Sources */, + 144F33C124C34A24006E4437 /* WKRDefaults.swift in Sources */, 146E054424AE3E9E001E1917 /* WKRPlayerRaceStats.swift in Sources */, 146E053324AE3E85001E1917 /* WKRReadyStates.swift in Sources */, 146E053A24AE3E8F001E1917 /* WKRLogEvent.swift in Sources */, @@ -637,8 +648,10 @@ 142CB29E202EC42000BC6A33 /* WKRPeerNetworkConfig.swift in Sources */, 149960702226FCBF00259B68 /* WKRDurationFormatter.swift in Sources */, 147EF6FE2202470700583D73 /* WKRSeenFinalArticlesStore.swift in Sources */, + 144F33C024C34A24006E4437 /* WKRDefaults.swift in Sources */, 140FCFCD1F3654EB00FFA84E /* WKRHistoryEntry.swift in Sources */, 141427FF21FBB84600C48788 /* WKRGameKitNetwork.swift in Sources */, + 140CE30424C2967900ECA175 /* WKRLanguageHackery.swift in Sources */, 14EB9F621F36832C00FF1A9E /* WKRMultiWindowNetwork.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -647,6 +660,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 144F33C224C34A24006E4437 /* WKRDefaults.swift in Sources */, 148164B11F5C94F200AC7178 /* WKRKitPageFetcherTests.swift in Sources */, 148164AF1F5C94E800AC7178 /* WKRKitRaceTests.swift in Sources */, 149FF8171F362B3D000A5D96 /* WKRKitTests.swift in Sources */, @@ -851,7 +865,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 13.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 2020.07; + MARKETING_VERSION = 2020.08; OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = com.andrewfinke.WKRKit; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; @@ -882,7 +896,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 13.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 2020.07; + MARKETING_VERSION = 2020.08; OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = com.andrewfinke.WKRKit; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; diff --git a/WKRKit/WKRKit/Game/WKRPreRaceConfig.swift b/WKRKit/WKRKit/Game/WKRPreRaceConfig.swift index d06502d..4eb3860 100644 --- a/WKRKit/WKRKit/Game/WKRPreRaceConfig.swift +++ b/WKRKit/WKRKit/Game/WKRPreRaceConfig.swift @@ -7,19 +7,20 @@ // import WKRUIKit +import os.log /// Used to transmit voting data and starting page public struct WKRPreRaceConfig: Codable, Equatable { - + // MARK: - Properties - + /// The voting info internal var votingState: WKRVotingState /// The starting page internal let startingPage: WKRPage - + // MARK: Initialization - + /// Creates a WKRPreRaceConfig object /// /// - Parameters: @@ -29,9 +30,9 @@ public struct WKRPreRaceConfig: Codable, Equatable { self.votingState = votingState self.startingPage = startingPage } - + // MARK: - Creation - + /// Creates a race config object based on starting page and voting data /// /// - Returns: The new race config @@ -42,50 +43,72 @@ public struct WKRPreRaceConfig: Codable, Equatable { } return (WKRRaceConfig(starting: startingPage, ending: page), logEvent) } - + /// Creates a WKRPreRaceConfig object /// /// - Parameter completionHandler: The handler holding the new config object static func new(settings: WKRGameSettings, completionHandler: @escaping ((_ config: WKRPreRaceConfig?, _ logEvents: [WKRLogEvent]) -> Void)) { var logEvents = [WKRLogEvent]() let operationQueue = OperationQueue() - + var potentialFinalPages = [WKRPage]() var startingPage: WKRPage? - + var fastlaneFinalPage: WKRPage? + let completedOperation = BlockOperation { // Used for quick debug to set first page to Apple and final page to first link on page. if WKRKitConstants.current.isQuickRaceMode { let startingURL = URL(string: "https://en.m.wikipedia.org/wiki/Apple_Inc.")! startingPage = WKRPage(title: "Apple Inc.", url: startingURL) - + let endingURL = URL(string: "https://en.m.wikipedia.org/wiki/Apple_Park")! let fakeEnd = WKRPage(title: "Apple Park", url: endingURL) - + potentialFinalPages.removeLast() potentialFinalPages.insert(fakeEnd, at: 0) } - + // Uses a set to remove any duplicates. This could happen if two final articles end up redirecting to the same page. let finalPages = Array(Set(potentialFinalPages.prefix(WKRKitConstants.current.votingArticlesCount))) - + let events = logEvents.compactMap { $0 } if !finalPages.isEmpty, let page = startingPage { - let config = WKRPreRaceConfig(startingPage: page, votingState: WKRVotingState(pages: finalPages)) + var config = WKRPreRaceConfig(startingPage: page, votingState: WKRVotingState(pages: finalPages)) + if WKRDefaults.isFastlaneSnapshotInstance, let page = fastlaneFinalPage { + config.votingState.fastlaneVotes(finalPage: page) + } completionHandler(config, events) } else { completionHandler(nil, events) } } - + // Gets the starting page let startingPageOperation = WKROperation() startingPageOperation.addExecutionBlock { [unowned startingPageOperation] in switch settings.startPage { case .random: - WKRPageFetcher.fetchRandom { page in - startingPage = page - startingPageOperation.state = .isFinished + if WKRDefaults.isFastlaneSnapshotInstance { + if WKRLanguageHackery.shared.isEnglish { + guard let url = URL(string: "https://en.m.wikipedia.org/wiki/Walt_Disney_World_Monorail_System") else { fatalError() } + startingPage = WKRPage(title: "Walt Disney World Monorail System", url: url) + startingPageOperation.state = .isFinished + } else { + WKRLanguageHackery.shared.adjustedPath(for: "/Walt_Disney") { path in + guard let path = path else { fatalError() } + WKRPageFetcher.fetch(path: path, useCache: true) { page, _ in + guard let page = page else { fatalError() } + startingPage = page + startingPageOperation.state = .isFinished + } + } + } + } else { + WKRPageFetcher.fetchRandom { page in + startingPage = page + startingPageOperation.state = .isFinished + os_log("fetched random start: %{public}s", log: .articlesValidation, type: .info, page?.title ?? "-") + } } case .custom(let page): startingPage = page @@ -93,7 +116,7 @@ public struct WKRPreRaceConfig: Codable, Equatable { } } completedOperation.addDependency(startingPageOperation) - + let endingPageOperations: [BlockOperation] switch settings.endPage { case .curatedVoting: @@ -104,39 +127,63 @@ public struct WKRPreRaceConfig: Codable, Equatable { } var randomPaths = [String]() let numberOfPagesToFetch = WKRKitConstants.current.votingArticlesCount + 1 - + // pages are suffled so we can just take index 0-n from the shuffled array for index in 0.. WKROperation in let operation = WKROperation() operation.addExecutionBlock { [unowned operation] in - // don't use cache to make sure to get most recent page - WKRPageFetcher.fetch(path: path, useCache: false) { page, isRedirect in - // 1. Make sure not redirect - // 2. Make sure page not nil - // 3. Make sure page not already in voting list for this race - // 4. Make sure page is not a link to a section "/USA#History" - // 5. Sometimes removed pages redirect to the Wikipedia homepage. - // 6. Make sure path in unseen - // 7/8. Make sure link not equal to starting page - if !isRedirect, - let page = page, - !potentialFinalPages.contains(page), - !page.url.absoluteString.contains("#"), - page.title != "Wikipedia, the free encyclopedia", - finalArticles.contains(page.path), - let startingPage = startingPage, - startingPage.url.absoluteString.lowercased() != page.url.absoluteString.lowercased() { - potentialFinalPages.append(page) - } else { - logEvents.append(WKRLogEvent(type: .votingArticleValidationFailure, - attributes: ["PagePath": path])) + + WKRLanguageHackery.shared.adjustedPath(for: path) { adjustedPath in + guard let adjustedPath = adjustedPath else { + operation.state = .isFinished + os_log("fetched error: no adjusted path", log: .articlesValidation, type: .error) + return + } + + // don't use cache to make sure to get most recent page + WKRPageFetcher.fetch(path: adjustedPath, useCache: false) { page, isRedirect in + // 1. Make sure not redirect + // 2. Make sure page not nil + // 3. Make sure page not already in voting list for this race + // 4. Make sure page is not a link to a section "/USA#History" + // 5. Sometimes removed pages redirect to the Wikipedia homepage. + // 6. Make sure path in unseen + // 7/8. Make sure link not equal to starting page + if !isRedirect, + let page = page, + !potentialFinalPages.contains(page), + !page.url.absoluteString.contains("#"), + page.title != "Wikipedia, the free encyclopedia", + let startingPage = startingPage, + startingPage.url.absoluteString.lowercased() != page.url.absoluteString.lowercased() { + potentialFinalPages.append(page) + os_log("fetched final: %{public}s", log: .articlesValidation, type: .info, page.title ?? "-") + } else { + logEvents.append(WKRLogEvent(type: .votingArticleValidationFailure, + attributes: ["PagePath": adjustedPath])) + os_log("fetched error final: %{public}s", log: .articlesValidation, type: .error, page?.title ?? "-") + } + + if WKRDefaults.isFastlaneSnapshotInstance && fastlanePath == path { + fastlaneFinalPage = page + } + operation.state = .isFinished } - operation.state = .isFinished } } operation.addDependency(startingPageOperation) @@ -145,7 +192,7 @@ public struct WKRPreRaceConfig: Codable, Equatable { } case .randomVoting: let numberOfPagesToFetch = Int(Double(WKRKitConstants.current.votingArticlesCount) * 1.5) - + // All the operations for get WKRPage objects to vote on endingPageOperations = (0.. WKROperation in let operation = WKROperation() @@ -157,7 +204,7 @@ public struct WKRPreRaceConfig: Codable, Equatable { let title = page.title, !page.url.absoluteString.contains("#"), title != "Wikipedia, the free encyclopedia", - title.count < WKRKitConstants.current.pageTitleMaxRandomLength { + title.count < WKRKitConstants.current.pageTitleMaxRandomLength { potentialFinalPages.append(page) } else { // Don't log the analytics, keep validation to just curated articles @@ -179,9 +226,9 @@ public struct WKRPreRaceConfig: Codable, Equatable { completedOperation.addDependency(operation) endingPageOperations = [operation] } - + operationQueue.addOperations([startingPageOperation, completedOperation], waitUntilFinished: false) operationQueue.addOperations(endingPageOperations, waitUntilFinished: false) } - + } diff --git a/WKRKit/WKRKit/Game/WKRRaceSettings.swift b/WKRKit/WKRKit/Game/WKRRaceSettings.swift index ac81bdf..6796ef1 100644 --- a/WKRKit/WKRKit/Game/WKRRaceSettings.swift +++ b/WKRKit/WKRKit/Game/WKRRaceSettings.swift @@ -106,6 +106,18 @@ public class WKRGameSettings: Codable { } } + public struct Language: Codable { + public let code: String + + public var isStandard: Bool { + return code == "en" + } + + public init(code: String) { + self.code = code + } + } + // MARK: - Properties - public var isCustom: Bool { @@ -114,7 +126,8 @@ public class WKRGameSettings: Codable { && timing.isStandard && other.isStandard && startPage.isStandard - && endPage.isStandard, + && endPage.isStandard + && language.isStandard, bannedPages.count == 1, case .portal = bannedPages[0] { return false @@ -137,6 +150,7 @@ public class WKRGameSettings: Codable { public var points = Points(bonusPointReward: WKRKitConstants.current.bonusPointReward, bonusPointsInterval: WKRKitConstants.current.bonusPointsInterval) public var timing = Timing(votingTime: WKRRaceDurationConstants.votingState, resultsTime: WKRRaceDurationConstants.resultsState) public var other = Other(isHelpEnabled: true) + public var language = Language(code: "en") public func reset() { startPage = .random diff --git a/WKRKit/WKRKit/Game/WKRVotingState.swift b/WKRKit/WKRKit/Game/WKRVotingState.swift index fddd55e..b4b62db 100644 --- a/WKRKit/WKRKit/Game/WKRVotingState.swift +++ b/WKRKit/WKRKit/Game/WKRVotingState.swift @@ -91,6 +91,19 @@ public struct WKRVotingState: Codable, Equatable { return (pagesWithMostVotes.randomElement, logEvent) } + mutating func fastlaneVotes(finalPage: WKRPage) { + var copy = pages + guard let index = copy.firstIndex(where: { $0 == finalPage }) else { fatalError() } + copy.remove(at: index) + copy.shuffle() + player(WKRPlayerProfile(name: "A", playerID: "A"), votedFor: finalPage) + player(WKRPlayerProfile(name: "G", playerID: "G"), votedFor: finalPage) + + player(WKRPlayerProfile(name: "C", playerID: "C"), votedFor: copy[0]) + player(WKRPlayerProfile(name: "M", playerID: "M"), votedFor: copy[1]) + player(WKRPlayerProfile(name: "X", playerID: "X"), votedFor: copy[2]) + } + // MARK: - Public Accessors public var current: [(page: WKRPage, voters: [WKRPlayerProfile])] { diff --git a/WKRKit/WKRKit/Info.plist b/WKRKit/WKRKit/Info.plist index af46f53..a3d7112 100644 --- a/WKRKit/WKRKit/Info.plist +++ b/WKRKit/WKRKit/Info.plist @@ -17,7 +17,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 13082 + 13396 NSPrincipalClass diff --git a/WKRKit/WKRKit/Manager/WKRManager+PageNavigation.swift b/WKRKit/WKRKit/Manager/WKRManager+PageNavigation.swift index acf4105..02a5d14 100644 --- a/WKRKit/WKRKit/Manager/WKRManager+PageNavigation.swift +++ b/WKRKit/WKRKit/Manager/WKRManager+PageNavigation.swift @@ -111,7 +111,7 @@ extension WKRGameManager { private func truncated(url: URL) -> String { var reportedURLString = url.absoluteString - if reportedURLString.starts(with: "https://en.m.wikipedia.org/wiki/") { + if reportedURLString.starts(with: WKRLanguageHackery.shared.baseURLString) { let index = reportedURLString.index(reportedURLString.startIndex, offsetBy: 31) reportedURLString = String(reportedURLString[index...]) } diff --git a/WKRKit/WKRKit/Manager/WKRManager.swift b/WKRKit/WKRKit/Manager/WKRManager.swift index 7cf3108..35d581f 100644 --- a/WKRKit/WKRKit/Manager/WKRManager.swift +++ b/WKRKit/WKRKit/Manager/WKRManager.swift @@ -89,6 +89,8 @@ final public class WKRGameManager { self.votingUpdate = votingUpdate self.resultsUpdate = resultsUpdate + WKRLanguageHackery.shared.configure(for: settings) + let setup = networkConfig.create() localPlayer = setup.player peerNetwork = setup.network diff --git a/WKRKit/WKRKit/Other/OSLog+WKRKit.swift b/WKRKit/WKRKit/Other/OSLog+WKRKit.swift index aed0144..87e3de4 100644 --- a/WKRKit/WKRKit/Other/OSLog+WKRKit.swift +++ b/WKRKit/WKRKit/Other/OSLog+WKRKit.swift @@ -14,7 +14,7 @@ extension OSLog { // MARK: - Types - private enum CustomCategory: String { - case constants, seenArticlesStore + case constants, seenArticlesStore, articlesValidation } private static let subsystem: String = { @@ -24,5 +24,6 @@ extension OSLog { static let constants = OSLog(subsystem: subsystem, category: CustomCategory.constants.rawValue) static let seenArticlesStore = OSLog(subsystem: subsystem, category: CustomCategory.seenArticlesStore.rawValue) + static let articlesValidation = OSLog(subsystem: subsystem, category: CustomCategory.articlesValidation.rawValue) } diff --git a/WKRKit/WKRKit/Other/WKRDefaults.swift b/WKRKit/WKRKit/Other/WKRDefaults.swift new file mode 100644 index 0000000..48517ca --- /dev/null +++ b/WKRKit/WKRKit/Other/WKRDefaults.swift @@ -0,0 +1,18 @@ +// +// WKRDefaults.swift +// WKRKit +// +// Created by Andrew Finke on 7/18/20. +// Copyright © 2020 Andrew Finke. All rights reserved. +// + +import Foundation + +struct WKRDefaults { + private static let fastlaneKey = "FASTLANE_SNAPSHOT" + static var isFastlaneSnapshotInstance: Bool { + get { + return UserDefaults.standard.bool(forKey: fastlaneKey) + } + } +} diff --git a/WKRKit/WKRKit/Other/WKRLanguageHackery.swift b/WKRKit/WKRKit/Other/WKRLanguageHackery.swift new file mode 100644 index 0000000..4fd80af --- /dev/null +++ b/WKRKit/WKRKit/Other/WKRLanguageHackery.swift @@ -0,0 +1,124 @@ +// +// WKRLanguageHackery.swift +// WKRKit +// +// Created by Andrew Finke on 7/17/20. +// Copyright © 2020 Andrew Finke. All rights reserved. +// + +import Foundation +import os.log + +/// A terrible, terrible approach, but I don't want to spend much time on this. + code quality/arch doesn't matter to me that much anymore given I will no longer be working on this project in a few weeks +internal class WKRLanguageHackery { + + // MARK: - Types- + + private struct WikiDataResponse: Decodable { + struct Entity: Decodable { + struct SiteLink: Decodable { + let url: String + } + let sitelinks: [String: SiteLink] + } + + private let entities: [String: Entity] + func path(for language: String) -> String? { + let site = "\(language).wikipedia.org/wiki" + let urlString = entities + .values + .map { $0.sitelinks.values } + .flatMap { $0 } + .map { $0.url } + .first(where: { $0.contains(site) }) + + guard let string = urlString else { + return nil + } + + let components = string.components(separatedBy: site) + guard components.count == 2 else { + return nil + } + + return components[1] + } + } + + // MARK: - Properties + + static private let session: URLSession = { + let config = URLSessionConfiguration.default + config.timeoutIntervalForRequest = 2 + config.timeoutIntervalForResource = 2 + return URLSession(configuration: config) + }() + + static let shared = WKRLanguageHackery() + private var language = "en" + + var isEnglish: Bool { + return language == "en" + } + + // MARK: - Initalization - + + private init() {} + + // MARK: - Helpers - + + func configure(for settings: WKRGameSettings) { + language = settings.language.code + } + + var baseURLString: String { + return WKRKitConstants.current.baseURLString.replacingOccurrences(of: "en", with: language) + } + + var whatLinksHereURLString: String { + return WKRKitConstants.current.whatLinksHereURLString.replacingOccurrences(of: "en", with: language) + } + + var randomURLString: String { + return WKRKitConstants.current.randomURLString.replacingOccurrences(of: "en", with: language) + } + + var pageTitleStringToReplace: String { + if language == "es" { + return " - Wikipedia, la enciclopedia libre" + } else if language == "fr" { + return " — Wikipédia" + } else if language == "de" { + return " – Wikipedia" + } else if language == "ru" { + return " — Википедия" + } else { + return WKRKitConstants.current.pageTitleStringToReplace + } + } + + func adjustedPath(for path: String, completion: @escaping ((String?) -> Void)) { + guard language != "en" else { + completion(path) + return + } + + let adjustedPath = path.dropFirst() + let urlString = "https://www.wikidata.org/w/api.php?action=wbgetentities&format=json&sites=enwiki&redirects=no&props=sitelinks%2Furls&titles=\(adjustedPath)" + guard let url = URL(string: urlString) else { + completion(nil) + return + } + let task = WKRLanguageHackery.session.dataTask(with: url) { data, _, _ in + if let data = data, let response = try? JSONDecoder().decode(WikiDataResponse.self, from: data) { + let newPath = response.path(for: self.language) + os_log("fetched adjusted path: %{public}s -> %{public}s", log: .articlesValidation, type: .info, path, newPath ?? "-") + completion(newPath) + } else { + completion(nil) + } + } + task.resume() + } + +} diff --git a/WKRKit/WKRKit/Pages/WKRPage.swift b/WKRKit/WKRKit/Pages/WKRPage.swift index 0e9eb9e..eeb83fb 100644 --- a/WKRKit/WKRKit/Pages/WKRPage.swift +++ b/WKRKit/WKRKit/Pages/WKRPage.swift @@ -31,7 +31,7 @@ public struct WKRPage: Codable, Hashable, Equatable { public init(title: String?, url: URL) { self.title = WKRPage.formattedTitle(for: title) self.url = url - self.path = url.absoluteString.replacingOccurrences(of: "https://en.m.wikipedia.org/wiki", with: "") + self.path = url.absoluteString.replacingOccurrences(of: WKRLanguageHackery.shared.baseURLString, with: "") } // MARK: - Helpers @@ -56,7 +56,7 @@ public struct WKRPage: Codable, Hashable, Equatable { return smartFormat(String(clippedTitle)) } else { // The expected path - let title = title.replacingOccurrences(of: WKRKitConstants.current.pageTitleStringToReplace, with: "") + let title = title.replacingOccurrences(of: WKRLanguageHackery.shared.pageTitleStringToReplace, with: "") return smartFormat(title) } } diff --git a/WKRKit/WKRKit/Pages/WKRPageFetcher.swift b/WKRKit/WKRKit/Pages/WKRPageFetcher.swift index dda02a1..ae4e6e1 100644 --- a/WKRKit/WKRKit/Pages/WKRPageFetcher.swift +++ b/WKRKit/WKRKit/Pages/WKRPageFetcher.swift @@ -35,8 +35,8 @@ public struct WKRPageFetcher { /// Returns the title from the raw HTML private static func title(from string: String) -> String? { guard let titleAttributeStart = string.range(of: ""), - let titleAttributeEnd = string.range(of: "") else { - return nil + let titleAttributeEnd = string.range(of: "") else { + return nil } let range = Range(uncheckedBounds: (titleAttributeStart.upperBound, titleAttributeEnd.lowerBound)) return String(string[range]) @@ -46,7 +46,7 @@ public struct WKRPageFetcher { /// Fetches Wikipedia page with path ("/Apple_Inc.") public static func fetch(path: String, useCache: Bool, completionHandler: @escaping ((_ page: WKRPage?, _ isRedirect: Bool) -> Void)) { - guard let url = URL(string: WKRKitConstants.current.baseURLString + path) else { + guard let url = URL(string: WKRLanguageHackery.shared.baseURLString + path) else { completionHandler(nil, false) return } @@ -55,7 +55,7 @@ public struct WKRPageFetcher { /// Fetches a random Wikipedia page static func fetchRandom(completionHandler: @escaping ((_ page: WKRPage?) -> Void)) { - guard let url = URL(string: WKRKitConstants.current.randomURLString) else { + guard let url = URL(string: WKRLanguageHackery.shared.randomURLString) else { completionHandler(nil) return } @@ -73,7 +73,11 @@ public struct WKRPageFetcher { session = WKRPageFetcher.noCacheSession } let task = session.dataTask(with: url) { (data, response, _) in - if let data = data, let string = String(data: data, encoding: .utf8), let responseUrl = response?.url { + if let response = response as? HTTPURLResponse, + response.statusCode != 404, + let data = data, + let string = String(data: data, encoding: .utf8), + let responseUrl = response.url { let page = WKRPage(title: title(from: string), url: responseUrl) let isRedirect = string.contains("Redirected from") completionHandler(page, isRedirect) @@ -87,7 +91,7 @@ public struct WKRPageFetcher { /// Fetches a Wikipedia page source. static func fetchSource(url: URL, useCache: Bool, - progressHandler: @escaping (_ progress: Float) -> Void, + progressHandler: ((_ progress: Float) -> Void)?, completionHandler: @escaping (_ source: String?, _ error: Error?) -> Void) { let session: URLSession if useCache { @@ -97,17 +101,24 @@ public struct WKRPageFetcher { } var observation: NSKeyValueObservation? - let task = session.dataTask(with: url) { (data, _, error) in + let task = session.dataTask(with: url) { (data, response, error) in observation?.invalidate() - if let data = data, let string = String(data: data, encoding: .utf8) { + if let response = response as? HTTPURLResponse, + response.statusCode != 404, + let data = data, + let string = String(data: data, encoding: .utf8) { completionHandler(string, nil) } else { completionHandler(nil, error) } } - observation = task.progress.observe(\.fractionCompleted) { progress, _ in - progressHandler(Float(progress.fractionCompleted)) + + if let progressHandler = progressHandler { + observation = task.progress.observe(\.fractionCompleted) { progress, _ in + progressHandler(Float(progress.fractionCompleted)) + } } + task.resume() } diff --git a/WKRKit/WKRKit/Web Logic/WKRLinkedPagesFetcher.swift b/WKRKit/WKRKit/Web Logic/WKRLinkedPagesFetcher.swift index fbd5768..06764a1 100644 --- a/WKRKit/WKRKit/Web Logic/WKRLinkedPagesFetcher.swift +++ b/WKRKit/WKRKit/Web Logic/WKRLinkedPagesFetcher.swift @@ -85,7 +85,7 @@ final internal class WKRLinkedPagesFetcher: NSObject, WKScriptMessageHandler { func start(for page: WKRPage) { let query = "&namespace=0&limit=500&hidetrans=1" - guard let url = URL(string: WKRKitConstants.current.whatLinksHereURLString + page.path + query) else { return } + guard let url = URL(string: WKRLanguageHackery.shared.whatLinksHereURLString + page.path + query) else { return } load(url: url) } diff --git a/WKRKit/WKRKit/Web Logic/WKRPageNavigation.swift b/WKRKit/WKRKit/Web Logic/WKRPageNavigation.swift index a13adb6..0c22814 100644 --- a/WKRKit/WKRKit/Web Logic/WKRPageNavigation.swift +++ b/WKRKit/WKRKit/Web Logic/WKRPageNavigation.swift @@ -73,7 +73,7 @@ final internal class WKRPageNavigation: NSObject, WKNavigationDelegate { } } - return urlString.contains(WKRKitConstants.current.baseURLString) + return urlString.contains(WKRLanguageHackery.shared.baseURLString) } // MARK: - WKNavigationDelegate diff --git a/WKRUIKit/WKRUIKit.xcodeproj/project.pbxproj b/WKRUIKit/WKRUIKit.xcodeproj/project.pbxproj index fafd711..44bc8f5 100644 --- a/WKRUIKit/WKRUIKit.xcodeproj/project.pbxproj +++ b/WKRUIKit/WKRUIKit.xcodeproj/project.pbxproj @@ -619,7 +619,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 13.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 2020.07; + MARKETING_VERSION = 2020.08; PRODUCT_BUNDLE_IDENTIFIER = com.andrewfinke.WKRUIKit; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -647,7 +647,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 13.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 2020.07; + MARKETING_VERSION = 2020.08; PRODUCT_BUNDLE_IDENTIFIER = com.andrewfinke.WKRUIKit; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/WKRUIKit/WKRUIKit/Constants/WKRUIKitConstants.swift b/WKRUIKit/WKRUIKit/Constants/WKRUIKitConstants.swift index a0fc0f7..8d63570 100644 --- a/WKRUIKit/WKRUIKit/Constants/WKRUIKitConstants.swift +++ b/WKRUIKit/WKRUIKit/Constants/WKRUIKitConstants.swift @@ -21,7 +21,7 @@ public struct WKRUIKitConstants { static let alertViewHeight: CGFloat = 50.0 static let alertViewImageHeight: CGFloat = 22 - static let alertViewImagePadding: CGFloat = 5 + static let alertViewImagePadding: CGFloat = 6 static let alertAnimateInDuration = 0.2 static let alertAnimateOutDuration = 0.15 public static let alertDefaultDuration = 3.0 diff --git a/WKRUIKit/WKRUIKit/Info.plist b/WKRUIKit/WKRUIKit/Info.plist index a40a2cf..4d9a996 100644 --- a/WKRUIKit/WKRUIKit/Info.plist +++ b/WKRUIKit/WKRUIKit/Info.plist @@ -17,7 +17,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 13985 + 14299 NSPrincipalClass diff --git a/WKRUIKit/WKRUIKit/WKRPlayerProfile.swift b/WKRUIKit/WKRUIKit/WKRPlayerProfile.swift index 3ee2f7a..8a4b745 100644 --- a/WKRUIKit/WKRUIKit/WKRPlayerProfile.swift +++ b/WKRUIKit/WKRUIKit/WKRPlayerProfile.swift @@ -11,30 +11,30 @@ import SwiftUI import UIKit public struct WKRPlayerProfile: Identifiable, Equatable, Hashable, Codable { - + // MARK: - Properties - - + public var id: String { return playerID } public let name: String public let playerID: String - + public var image: Image { Image(uiImage: rawImage) } public var rawImage: UIImage { WKRUIPlayerImageManager.shared.image(for: name) } // MARK: - Initalization - - + public init(name: String, playerID: String) { self.name = name self.playerID = playerID } - + public init(player: GKPlayer) { self.name = player.displayName self.playerID = player.alias } - + public static func ==(lhs: WKRPlayerProfile, rhs: WKRPlayerProfile) -> Bool { return lhs.playerID == rhs.playerID } diff --git a/WKRUIKit/WKRUIKit/WKRUIPlayerImageManager.swift b/WKRUIKit/WKRUIKit/WKRUIPlayerImageManager.swift index 0943bc0..ca4ca06 100644 --- a/WKRUIKit/WKRUIKit/WKRUIPlayerImageManager.swift +++ b/WKRUIKit/WKRUIKit/WKRUIPlayerImageManager.swift @@ -70,7 +70,7 @@ public class WKRUIPlayerImageManager { } } } - + @discardableResult private func generatePlaceholder(for player: String) -> UIImage { let placeholder = WKRUIPlayerPlaceholderImageRenderer.render(name: player) diff --git a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/CustomRaceViewController/CustomRaceLanguageController.swift b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/CustomRaceViewController/CustomRaceLanguageController.swift new file mode 100644 index 0000000..a5de030 --- /dev/null +++ b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/CustomRaceViewController/CustomRaceLanguageController.swift @@ -0,0 +1,123 @@ +// +// CustomRaceLanguageController.swift +// WikiRaces +// +// Created by Andrew Finke on 7/17/20. +// Copyright © 2020 Andrew Finke. All rights reserved. +// + +import UIKit +import WKRKit + +final class CustomRaceLanguageController: CustomRaceController { + + // MARK: - Types - + + private class Cell: UITableViewCell, UITextFieldDelegate { + + // MARK: - Properties - + + let textField = UITextField() + static let reuseIdentifier = "reuseIdentifier" + + // MARK: - Initalization - + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + textField.textAlignment = .right + textField.returnKeyType = .done + textField.delegate = self + contentView.addSubview(textField) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - View Life Cycle - + + override func layoutSubviews() { + super.layoutSubviews() + textField.frame = CGRect(origin: .zero, size: CGSize(width: 80, height: contentView.frame.height)) + textField.center = CGPoint( + x: contentView.frame.width - contentView.layoutMargins.right - textField.frame.width / 2, + y: contentView.frame.height / 2) + } + + // MARK: - UITextFieldDelegate - + + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + textField.resignFirstResponder() + return true + } + } + + // MARK: - Properties - + + var language: WKRGameSettings.Language { + didSet { + didUpdate?(language) + } + } + var didUpdate: ((WKRGameSettings.Language) -> Void)? + private var textField: UITextField? + + // MARK: - Initalization - + + init(language: WKRGameSettings.Language) { + self.language = language + super.init(style: .grouped) + title = "Language".uppercased() + tableView.allowsSelection = false + tableView.register(Cell.self, forCellReuseIdentifier: Cell.reuseIdentifier) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - View Life Cycle - + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + if let text = textField?.text?.lowercased(), text != language.code { + language = WKRGameSettings.Language(code: text) + } + } + + // MARK: - UITableViewDataSource - + + override func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return 1 + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + guard let cell = tableView.dequeueReusableCell(withIdentifier: Cell.reuseIdentifier, + for: indexPath) as? Cell else { + fatalError() + } + switch indexPath.row { + case 0: + cell.textLabel?.text = "Language Code" + cell.textField.text = language.code.lowercased() + textField = cell.textField + default: + fatalError() + } + + return cell + } + + override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { + return """ + Changing the Wikipedia language is highly experimental and not fully tested. + + Some aspects of the game may not work as expected when using any language other than the standard English Wikipedia (“en”). + """ + } + +} diff --git a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/CustomRaceViewController/CustomRaceViewController.swift b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/CustomRaceViewController/CustomRaceViewController.swift index bda358e..707a710 100644 --- a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/CustomRaceViewController/CustomRaceViewController.swift +++ b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/CustomRaceViewController/CustomRaceViewController.swift @@ -19,7 +19,7 @@ final class CustomRaceViewController: CustomRaceController { case endPage = "End Page" case bannedPages = "Banned Pages" case notifications = "Player Messages" - case points, timing, other + case points, timing, other, language } // MARK: - Properties - @@ -217,6 +217,16 @@ final class CustomRaceViewController: CustomRaceController { tableView.reloadData() } } + case .language: + let controller = CustomRaceLanguageController(language: settings.language) + navigationController?.pushViewController(controller, animated: true) + controller.didUpdate = { [weak self] language in + guard let self = self else { return } + self.settings.language = language + DispatchQueue.main.async { + tableView.reloadData() + } + } } } @@ -266,6 +276,12 @@ final class CustomRaceViewController: CustomRaceController { } case .other: return "" + case .language: + if settings.language.isStandard { + return "English" + } else { + return settings.language.code.lowercased() + } } } diff --git a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/GKHostViewController/GKHostViewController+Match.swift b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/GKHostViewController/GKHostViewController+Match.swift index 6dc8079..f6f7d20 100644 --- a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/GKHostViewController/GKHostViewController+Match.swift +++ b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/GKHostViewController/GKHostViewController+Match.swift @@ -62,7 +62,12 @@ extension GKHostViewController: GKMatchDelegate { self.match?.delegate = self self.addPlayers() } else { - fatalError() + os_log("%{public}s- gamekit did the impossible, no error, no match, nothing to see here", log: .gameKit, type: .error, #function) + DispatchQueue.main.async { + self.isMatchmakingEnabled = false + self.showError(title: "Failed to Create Race", message: "Please try again later.") + self.model.state = .soloRace + } } } diff --git a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/GKHostViewController/GKHostViewController.swift b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/GKHostViewController/GKHostViewController.swift index 68b4451..a27127f 100644 --- a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/GKHostViewController/GKHostViewController.swift +++ b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/GKHostViewController/GKHostViewController.swift @@ -52,8 +52,18 @@ final internal class GKHostViewController: GKConnectViewController { init() { super.init(isPlayerHost: true) - startMatchmaking() - WKRSeenFinalArticlesStore.resetRemotePlayersSeenFinalArticles() + if Defaults.isFastlaneSnapshotInstance { + model.raceCode = "APPLE" + model.state = .showingRacers + model.connectedPlayers = [ + WKRPlayerProfile(name: "C", playerID: "C"), + WKRPlayerProfile(name: "G", playerID: "G"), + WKRPlayerProfile(name: "M", playerID: "M"), + WKRPlayerProfile(name: "X", playerID: "X") + ] + } else { + startMatchmaking() + } } required init?(coder: NSCoder) { @@ -76,7 +86,7 @@ final internal class GKHostViewController: GKConnectViewController { self?.contentViewHosting.view.alpha = 1 } - guard !Defaults.promptedAutoInvite else { + guard !Defaults.promptedAutoInvite && !Defaults.isFastlaneSnapshotInstance else { return } Defaults.promptedAutoInvite = true @@ -97,6 +107,7 @@ final internal class GKHostViewController: GKConnectViewController { os_log("%{public}s: disabled auto invite", log: .gameKit, type: .info, #function) } controller.addAction(cancelAction) + present(controller, animated: true, completion: nil) } @@ -108,6 +119,18 @@ final internal class GKHostViewController: GKConnectViewController { // MARK: - Actions - func startMatch() { + if Defaults.isFastlaneSnapshotInstance { + guard let code = Locale.preferredLanguages.first?.split(separator: "-").first else { fatalError() } + model.settings.language = WKRGameSettings.Language(code: String(code)) + let controller = GameViewController(network: .solo(name: "_"), settings: model.settings) + let nav = WKRUINavigationController(rootViewController: controller) + nav.modalPresentationStyle = .fullScreen + nav.modalTransitionStyle = .crossDissolve + nav.isModalInPresentation = true + present(nav, animated: false) + return + } + os_log("%{public}s", log: .gameKit, type: .info, #function) PlayerFirebaseAnalytics.log(event: .userAction(#function)) diff --git a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/GKHostViewController/SwiftUI/HostContentView.swift b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/GKHostViewController/SwiftUI/HostContentView.swift index fce3e69..628119e 100644 --- a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/GKHostViewController/SwiftUI/HostContentView.swift +++ b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/GKHostViewController/SwiftUI/HostContentView.swift @@ -55,13 +55,22 @@ struct HostContentView: View { .allowsHitTesting(model.state != .raceStarting) Spacer() - WKRUIPlayerImageView( - player: WKRPlayerProfile(player: GKLocalPlayer.local), - size: 100, - effectSize: 5) - .padding(.bottom, 20) + if Defaults.isFastlaneSnapshotInstance { + WKRUIPlayerImageView( + player: WKRPlayerProfile(name: "A", playerID: "A"), + size: 100, + effectSize: 5) + .padding(.bottom, 20) + } else { + WKRUIPlayerImageView( + player: WKRPlayerProfile(player: GKLocalPlayer.local), + size: 100, + effectSize: 5) + .padding(.bottom, 20) + } + - if !WKRUIPlayerImageManager.shared.isLocalPlayerImageFromGameCenter { + if !WKRUIPlayerImageManager.shared.isLocalPlayerImageFromGameCenter && !Defaults.isFastlaneSnapshotInstance { HStack { Spacer() Text("Set a custom racer photo\nin the Game Center settings") diff --git a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MenuView+Actions.swift b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MenuView+Actions.swift index 160ae7b..b25c565 100644 --- a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MenuView+Actions.swift +++ b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MenuView+Actions.swift @@ -31,7 +31,7 @@ extension MenuView { PlayerCloudKitLiveRaceManager.shared.isCloudEnabled { isEnabled in DispatchQueue.main.async { - if isEnabled { + if isEnabled || Defaults.isFastlaneSnapshotInstance { self.animateMenuOut { self.listenerUpdate?(.presentCreateRace) } diff --git a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuViewController.swift b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuViewController.swift index d1e8da6..323c5f2 100644 --- a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuViewController.swift +++ b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuViewController.swift @@ -209,10 +209,15 @@ final internal class MenuViewController: UIViewController { func createRace() { if Defaults.isFastlaneSnapshotInstance { - let controller = GameViewController(network: .solo(name: "_"), settings: WKRGameSettings()) + for player in ["A", "C", "G", "M", "X"] { + let _ = WKRUIPlayerImageManager.shared.image(for: player) + } + + let controller = GKHostViewController() let nav = WKRUINavigationController(rootViewController: controller) nav.modalPresentationStyle = .overCurrentContext - present(nav, animated: true, completion: nil) + nav.setNavigationBarHidden(true, animated: false) + present(nav, animated: false, completion: nil) } else { prepareForRace(completion: { let controller = RaceChecksViewController(destination: .hostPrivate) diff --git a/WikiRaces/Shared/Other/GameKit Support/GKMatchRequest+WKR.swift b/WikiRaces/Shared/Other/GameKit Support/GKMatchRequest+WKR.swift index 36dee42..b1e7329 100644 --- a/WikiRaces/Shared/Other/GameKit Support/GKMatchRequest+WKR.swift +++ b/WikiRaces/Shared/Other/GameKit Support/GKMatchRequest+WKR.swift @@ -61,6 +61,6 @@ extension GKMatchRequest { } private static func publicRacePlayerGroup() -> Int { - return 10 + return 11 } } diff --git a/WikiRaces/Shared/Other/GameKit Support/RaceCodeGenerator.swift b/WikiRaces/Shared/Other/GameKit Support/RaceCodeGenerator.swift index 158eb42..c3cc5b1 100644 --- a/WikiRaces/Shared/Other/GameKit Support/RaceCodeGenerator.swift +++ b/WikiRaces/Shared/Other/GameKit Support/RaceCodeGenerator.swift @@ -102,7 +102,7 @@ class RaceCodeGenerator { guard raceCode.count < 10 else { return -1 } let formattedCode = raceCode.lowercased() - var playerGroup = formattedCode.count + var playerGroup = formattedCode.count + 1 // + X == force version compatibility due to App Store Connect being broken for (index, char) in formattedCode.enumerated() { let charValue: Int = (validCharactersArray.firstIndex(of: char) ?? 50) + 1 let offset = Int(pow(Double(10), Double(index * 2) + 1)) diff --git a/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController+UI.swift b/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController+UI.swift index cb62f71..0c5980f 100644 --- a/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController+UI.swift +++ b/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController+UI.swift @@ -39,10 +39,6 @@ extension GameViewController { navigationItem.leftBarButtonItem = nil navigationItem.rightBarButtonItem = nil - if Defaults.isFastlaneSnapshotInstance { - navigationItem.leftBarButtonItem = helpBarButtonItem - navigationItem.rightBarButtonItem = quitBarButtonItem - } navigationView.addSubview(navigationBarBottomLine) setupElements() @@ -64,7 +60,6 @@ extension GameViewController { ] NSLayoutConstraint.activate(constraints) -// view.alpha = 0 navigationController.setNavigationBarHidden(true, animated: false) } @@ -117,9 +112,7 @@ extension GameViewController { ] NSLayoutConstraint.activate(constraints) - if !Defaults.isFastlaneSnapshotInstance { - gameManager.webView = webView - } + gameManager.webView = webView self.webView = webView } diff --git a/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController.swift b/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController.swift index 0a3bb48..60dabcd 100644 --- a/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController.swift +++ b/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController.swift @@ -92,24 +92,13 @@ final internal class GameViewController: UIViewController { // MARK: - View Life Cycle override func viewDidLoad() { - super.viewDidLoad() - if Defaults.isFastlaneSnapshotInstance { - setupInterface() - let url = URL(string: "https://en.m.wikipedia.org/wiki/Walt_Disney_World_Monorail_System")! - prepareForScreenshots(for: url) - } else { - setupGameManager() - setupInterface() - } + setupGameManager() + setupInterface() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) -// if Defaults.isFastlaneSnapshotInstance { -// return -// } - if !isConfigured { isConfigured = true initalConfiguration() diff --git a/WikiRaces/WikiRaces.xcodeproj/project.pbxproj b/WikiRaces/WikiRaces.xcodeproj/project.pbxproj index 07c583d..894f02c 100644 --- a/WikiRaces/WikiRaces.xcodeproj/project.pbxproj +++ b/WikiRaces/WikiRaces.xcodeproj/project.pbxproj @@ -7,6 +7,11 @@ objects = { /* Begin PBXBuildFile section */ + 140CE2FB24C292F000ECA175 /* CustomRaceLanguageController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140CE2FA24C292F000ECA175 /* CustomRaceLanguageController.swift */; }; + 140CE2FC24C292F000ECA175 /* CustomRaceLanguageController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140CE2FA24C292F000ECA175 /* CustomRaceLanguageController.swift */; }; + 140CE2FD24C292F000ECA175 /* CustomRaceLanguageController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140CE2FA24C292F000ECA175 /* CustomRaceLanguageController.swift */; }; + 140CE2FE24C292F000ECA175 /* CustomRaceLanguageController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140CE2FA24C292F000ECA175 /* CustomRaceLanguageController.swift */; }; + 140CE2FF24C292F000ECA175 /* CustomRaceLanguageController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140CE2FA24C292F000ECA175 /* CustomRaceLanguageController.swift */; }; 1410DB3B1F4F510900F5CAD7 /* SharedAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1410DB3A1F4F510900F5CAD7 /* SharedAssets.xcassets */; }; 1410DB3D1F4F510900F5CAD7 /* SharedAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1410DB3A1F4F510900F5CAD7 /* SharedAssets.xcassets */; }; 1414280321FC18F600C48788 /* GKJoinViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1414280221FC18F600C48788 /* GKJoinViewController.swift */; }; @@ -80,6 +85,25 @@ 144EC2A724ADA93500F0C315 /* BackingVisualEffectViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 144EC2A424ADA93500F0C315 /* BackingVisualEffectViewController.swift */; }; 144EC2A824ADA93500F0C315 /* BackingVisualEffectViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 144EC2A424ADA93500F0C315 /* BackingVisualEffectViewController.swift */; }; 144EC2A924ADA93500F0C315 /* BackingVisualEffectViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 144EC2A424ADA93500F0C315 /* BackingVisualEffectViewController.swift */; }; + 144F33AC24C345AB006E4437 /* FirebaseABTesting.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14F23FDD24A78DF900820638 /* FirebaseABTesting.xcframework */; }; + 144F33AD24C345AB006E4437 /* FirebaseCore.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14F23FE524A78DF900820638 /* FirebaseCore.xcframework */; }; + 144F33AE24C345AB006E4437 /* FirebaseCoreDiagnostics.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14F23FF224A78DFA00820638 /* FirebaseCoreDiagnostics.xcframework */; }; + 144F33AF24C345AB006E4437 /* FirebaseCrashlytics.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14F23FE424A78DF900820638 /* FirebaseCrashlytics.xcframework */; }; + 144F33B024C345AB006E4437 /* FirebaseInstallations.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14F23FEB24A78DFA00820638 /* FirebaseInstallations.xcframework */; }; + 144F33B124C345AB006E4437 /* FirebaseInstanceID.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14F23FDF24A78DF900820638 /* FirebaseInstanceID.xcframework */; }; + 144F33B224C345AB006E4437 /* FirebaseRemoteConfig.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14F23FE024A78DF900820638 /* FirebaseRemoteConfig.xcframework */; }; + 144F33B324C345AB006E4437 /* GoogleDataTransport.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14F23FE324A78DF900820638 /* GoogleDataTransport.xcframework */; }; + 144F33B424C345AB006E4437 /* GoogleDataTransportCCTSupport.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14F23FDB24A78DF900820638 /* GoogleDataTransportCCTSupport.xcframework */; }; + 144F33B524C345AB006E4437 /* GoogleToolboxForMac.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14F23FE624A78DF900820638 /* GoogleToolboxForMac.xcframework */; }; + 144F33B624C345AB006E4437 /* GoogleUtilities.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14F23FE724A78DF900820638 /* GoogleUtilities.xcframework */; }; + 144F33B724C345AB006E4437 /* GTMSessionFetcher.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14F23FE124A78DF900820638 /* GTMSessionFetcher.xcframework */; }; + 144F33B824C345AB006E4437 /* nanopb.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14F23FEF24A78DFA00820638 /* nanopb.xcframework */; }; + 144F33B924C345AB006E4437 /* PromisesObjC.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14F23FF024A78DFA00820638 /* PromisesObjC.xcframework */; }; + 144F33BA24C345AB006E4437 /* Protobuf.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14F23FDE24A78DF900820638 /* Protobuf.xcframework */; }; + 144F33BB24C345AE006E4437 /* FirebasePerformance.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14F23FED24A78DFA00820638 /* FirebasePerformance.framework */; }; + 144F33BC24C345AE006E4437 /* GoogleAppMeasurement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14F23FEE24A78DFA00820638 /* GoogleAppMeasurement.framework */; }; + 144F33BD24C345AE006E4437 /* FirebaseAnalytics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14F23FEC24A78DFA00820638 /* FirebaseAnalytics.framework */; }; + 144F33BE24C345AE006E4437 /* FIRAnalyticsConnector.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14F23FF124A78DFA00820638 /* FIRAnalyticsConnector.framework */; }; 14584BC2220B6BE700D63428 /* WKRKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14E6D55A1F86A1B0005EB3B9 /* WKRKit.framework */; }; 14584BC3220B6BE700D63428 /* WKRKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 14E6D55A1F86A1B0005EB3B9 /* WKRKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 14584BC7220B6BEE00D63428 /* WKRUIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14E6D5521F86A1B0005EB3B9 /* WKRUIKit.framework */; }; @@ -650,6 +674,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 140CE2FA24C292F000ECA175 /* CustomRaceLanguageController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomRaceLanguageController.swift; sourceTree = ""; }; 1410DB3A1F4F510900F5CAD7 /* SharedAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = SharedAssets.xcassets; sourceTree = ""; }; 1414280221FC18F600C48788 /* GKJoinViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GKJoinViewController.swift; sourceTree = ""; }; 1414280621FC394600C48788 /* GKConnectViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GKConnectViewController.swift; sourceTree = ""; }; @@ -759,7 +784,6 @@ 14EBF58624A4D8260040A7C0 /* HostContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostContentView.swift; sourceTree = ""; }; 14EBF59824A4F3E20040A7C0 /* ActivityIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityIndicatorView.swift; sourceTree = ""; }; 14EBF59E24A4F43A0040A7C0 /* HostContentViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostContentViewModel.swift; sourceTree = ""; }; - 14EBF5A524A4F4680040A7C0 /* PlayerImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerImageView.swift; sourceTree = ""; }; 14EBF5AB24A4F4780040A7C0 /* HostSectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostSectionView.swift; sourceTree = ""; }; 14EF51CA245FAE5500F3653F /* CustomRaceOtherController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomRaceOtherController.swift; sourceTree = ""; }; 14EF51CB245FAE5500F3653F /* CustomRacePageViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomRacePageViewController.swift; sourceTree = ""; }; @@ -858,6 +882,25 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 144F33AF24C345AB006E4437 /* FirebaseCrashlytics.xcframework in Frameworks */, + 144F33BC24C345AE006E4437 /* GoogleAppMeasurement.framework in Frameworks */, + 144F33BD24C345AE006E4437 /* FirebaseAnalytics.framework in Frameworks */, + 144F33B024C345AB006E4437 /* FirebaseInstallations.xcframework in Frameworks */, + 144F33B524C345AB006E4437 /* GoogleToolboxForMac.xcframework in Frameworks */, + 144F33B924C345AB006E4437 /* PromisesObjC.xcframework in Frameworks */, + 144F33B324C345AB006E4437 /* GoogleDataTransport.xcframework in Frameworks */, + 144F33B824C345AB006E4437 /* nanopb.xcframework in Frameworks */, + 144F33B624C345AB006E4437 /* GoogleUtilities.xcframework in Frameworks */, + 144F33B724C345AB006E4437 /* GTMSessionFetcher.xcframework in Frameworks */, + 144F33B424C345AB006E4437 /* GoogleDataTransportCCTSupport.xcframework in Frameworks */, + 144F33BA24C345AB006E4437 /* Protobuf.xcframework in Frameworks */, + 144F33B224C345AB006E4437 /* FirebaseRemoteConfig.xcframework in Frameworks */, + 144F33AC24C345AB006E4437 /* FirebaseABTesting.xcframework in Frameworks */, + 144F33BB24C345AE006E4437 /* FirebasePerformance.framework in Frameworks */, + 144F33AE24C345AB006E4437 /* FirebaseCoreDiagnostics.xcframework in Frameworks */, + 144F33B124C345AB006E4437 /* FirebaseInstanceID.xcframework in Frameworks */, + 144F33AD24C345AB006E4437 /* FirebaseCore.xcframework in Frameworks */, + 144F33BE24C345AE006E4437 /* FIRAnalyticsConnector.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -924,24 +967,24 @@ 143054C01F8958DC00C0BC27 /* Analytics */ = { isa = PBXGroup; children = ( - 14F23FF124A78DFA00820638 /* FIRAnalyticsConnector.framework */, 14F23FE224A78DF900820638 /* Firebase.h */, - 14F23FDD24A78DF900820638 /* FirebaseABTesting.xcframework */, + 14F23FDC24A78DF900820638 /* module.modulemap */, + 14F23FED24A78DFA00820638 /* FirebasePerformance.framework */, + 14F23FEE24A78DFA00820638 /* GoogleAppMeasurement.framework */, 14F23FEC24A78DFA00820638 /* FirebaseAnalytics.framework */, + 14F23FF124A78DFA00820638 /* FIRAnalyticsConnector.framework */, + 14F23FDD24A78DF900820638 /* FirebaseABTesting.xcframework */, 14F23FE524A78DF900820638 /* FirebaseCore.xcframework */, 14F23FF224A78DFA00820638 /* FirebaseCoreDiagnostics.xcframework */, 14F23FE424A78DF900820638 /* FirebaseCrashlytics.xcframework */, 14F23FEB24A78DFA00820638 /* FirebaseInstallations.xcframework */, 14F23FDF24A78DF900820638 /* FirebaseInstanceID.xcframework */, - 14F23FED24A78DFA00820638 /* FirebasePerformance.framework */, 14F23FE024A78DF900820638 /* FirebaseRemoteConfig.xcframework */, - 14F23FEE24A78DFA00820638 /* GoogleAppMeasurement.framework */, 14F23FE324A78DF900820638 /* GoogleDataTransport.xcframework */, 14F23FDB24A78DF900820638 /* GoogleDataTransportCCTSupport.xcframework */, 14F23FE624A78DF900820638 /* GoogleToolboxForMac.xcframework */, 14F23FE724A78DF900820638 /* GoogleUtilities.xcframework */, 14F23FE124A78DF900820638 /* GTMSessionFetcher.xcframework */, - 14F23FDC24A78DF900820638 /* module.modulemap */, 14F23FEF24A78DFA00820638 /* nanopb.xcframework */, 14F23FF024A78DFA00820638 /* PromisesObjC.xcframework */, 14F23FDE24A78DF900820638 /* Protobuf.xcframework */, @@ -1308,7 +1351,6 @@ 14EBF59E24A4F43A0040A7C0 /* HostContentViewModel.swift */, 14EBF58624A4D8260040A7C0 /* HostContentView.swift */, 14EBF5AB24A4F4780040A7C0 /* HostSectionView.swift */, - 14EBF5A524A4F4680040A7C0 /* PlayerImageView.swift */, 14EBF59824A4F3E20040A7C0 /* ActivityIndicatorView.swift */, ); path = SwiftUI; @@ -1333,6 +1375,7 @@ 14EF51CE245FAE5600F3653F /* CustomRaceNumericalViewController.swift */, 14EF51CA245FAE5500F3653F /* CustomRaceOtherController.swift */, 14EF51CB245FAE5500F3653F /* CustomRacePageViewController.swift */, + 140CE2FA24C292F000ECA175 /* CustomRaceLanguageController.swift */, ); path = CustomRaceViewController; sourceTree = ""; @@ -1726,6 +1769,7 @@ 14EF51DB245FAE5600F3653F /* CustomRaceNotificationsController.swift in Sources */, 14EF51DE245FAE5600F3653F /* CustomRaceNumericalViewController.swift in Sources */, 142ABE0624600A74008E7F77 /* PlusStore.swift in Sources */, + 140CE2FB24C292F000ECA175 /* CustomRaceLanguageController.swift in Sources */, 142ABDFA24600559008E7F77 /* PlusViewController.swift in Sources */, 14DB8C9924AC2A8400D356DF /* OSLog+WikiRaces.swift in Sources */, 14EBF50B24A49BF20040A7C0 /* VotingContentViewModel.swift in Sources */, @@ -1788,6 +1832,7 @@ 142ABDFF24600576008E7F77 /* PlusView.swift in Sources */, 14B2DD4622212B96009B8AB3 /* MenuView+Setup.swift in Sources */, 14B4DB662224F1B9007D4B54 /* GKJoinViewController.swift in Sources */, + 140CE2FC24C292F000ECA175 /* CustomRaceLanguageController.swift in Sources */, 14C4AB5B1F368A050086B77F /* HistoryViewController.swift in Sources */, 1475C14624A655B000882F1F /* GameViewController+KB.swift in Sources */, 1446C1E124A337DD000A0ED3 /* GKHostViewController+Match.swift in Sources */, @@ -1904,6 +1949,7 @@ 14DB8C9B24AC2A8400D356DF /* OSLog+WikiRaces.swift in Sources */, 1475C13924A6555B00882F1F /* VisualEffectViewController.swift in Sources */, 1475C19E24A6560800882F1F /* ResultsViewController+KB.swift in Sources */, + 140CE2FD24C292F000ECA175 /* CustomRaceLanguageController.swift in Sources */, 1475C14824A655B100882F1F /* GameViewController+Manager.swift in Sources */, 1475C18024A655F100882F1F /* StatsPlayersViewController.swift in Sources */, 1475C13D24A6556A00882F1F /* PlayerFirebaseAnalytics.swift in Sources */, @@ -1966,6 +2012,7 @@ 14B2DD4722212B96009B8AB3 /* MenuView+Setup.swift in Sources */, 1475C1A124A6560D00882F1F /* HistoryViewController.swift in Sources */, 14C25FFF1F6F02A500CD7373 /* ResultsViewController.swift in Sources */, + 140CE2FE24C292F000ECA175 /* CustomRaceLanguageController.swift in Sources */, 14B4DB672224F1BA007D4B54 /* GKJoinViewController.swift in Sources */, 1475C1A324A6560D00882F1F /* HistoryTableViewCell.swift in Sources */, 14EF51D7245FAE5600F3653F /* CustomRacePageViewController.swift in Sources */, @@ -2065,6 +2112,7 @@ 1475C17E24A655F000882F1F /* StatsPlayersViewController.swift in Sources */, 148E5C6424A2AE7D00DD43E4 /* RaceCodeGenerator.swift in Sources */, 148E5C4624A293DD00DD43E4 /* NearbyRaceAdvertiser.swift in Sources */, + 140CE2FF24C292F000ECA175 /* CustomRaceLanguageController.swift in Sources */, 1475C13124A6553F00882F1F /* ResultsContentView.swift in Sources */, 148E5C5224A2943100DD43E4 /* Nearby.swift in Sources */, 14EBF50F24A49BF20040A7C0 /* VotingContentViewModel.swift in Sources */, @@ -2341,7 +2389,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2020.07.2; + MARKETING_VERSION = 2020.08; OTHER_LDFLAGS = "-ObjC"; OTHER_SWIFT_FLAGS = "-Xfrontend -warn-long-function-bodies=300 -Xfrontend -warn-long-expression-type-checking=150"; PRODUCT_BUNDLE_IDENTIFIER = com.andrewfinke.wikiraces; @@ -2376,7 +2424,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2020.07.2; + MARKETING_VERSION = 2020.08; OTHER_LDFLAGS = "-ObjC"; PRODUCT_BUNDLE_IDENTIFIER = com.andrewfinke.wikiraces; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2447,6 +2495,7 @@ "$(PROJECT_DIR)/Shared/Frameworks/Analytics", ); INFOPLIST_FILE = WikiRacesScreenshots/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.1; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -2469,6 +2518,7 @@ "$(PROJECT_DIR)/Shared/Frameworks/Analytics", ); INFOPLIST_FILE = WikiRacesScreenshots/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.1; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/WikiRaces/WikiRaces.xcodeproj/xcshareddata/xcschemes/WikiRacesScreenshots.xcscheme b/WikiRaces/WikiRaces.xcodeproj/xcshareddata/xcschemes/WikiRacesScreenshots.xcscheme index ecb350c..e9c9900 100644 --- a/WikiRaces/WikiRaces.xcodeproj/xcshareddata/xcschemes/WikiRacesScreenshots.xcscheme +++ b/WikiRaces/WikiRaces.xcodeproj/xcshareddata/xcschemes/WikiRacesScreenshots.xcscheme @@ -1,7 +1,7 @@ + version = "1.3"> @@ -27,24 +27,6 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> - - - - - - - - - - diff --git a/WikiRaces/WikiRaces/Info.plist b/WikiRaces/WikiRaces/Info.plist index d1a7ad1..94a90b5 100644 --- a/WikiRaces/WikiRaces/Info.plist +++ b/WikiRaces/WikiRaces/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 8776 + 8994 ITSAppUsesNonExemptEncryption LSApplicationCategoryType diff --git a/WikiRaces/WikiRacesScreenshots/SnapshotHelper.swift b/WikiRaces/WikiRacesScreenshots/SnapshotHelper.swift index c86ccde..f5b393c 100755 --- a/WikiRaces/WikiRacesScreenshots/SnapshotHelper.swift +++ b/WikiRaces/WikiRacesScreenshots/SnapshotHelper.swift @@ -38,22 +38,13 @@ func snapshot(_ name: String, timeWaitingForIdle timeout: TimeInterval = 20) { } enum SnapshotError: Error, CustomDebugStringConvertible { - case cannotDetectUser - case cannotFindHomeDirectory case cannotFindSimulatorHomeDirectory - case cannotAccessSimulatorHomeDirectory(String) case cannotRunOnPhysicalDevice var debugDescription: String { switch self { - case .cannotDetectUser: - return "Couldn't find Snapshot configuration files - can't detect current user " - case .cannotFindHomeDirectory: - return "Couldn't find Snapshot configuration files - can't detect `Users` dir" case .cannotFindSimulatorHomeDirectory: return "Couldn't find simulator home location. Please, check SIMULATOR_HOST_HOME env variable." - case .cannotAccessSimulatorHomeDirectory(let simulatorHostHome): - return "Can't prepare environment. Simulator home location is inaccessible. Does \(simulatorHostHome) exist?" case .cannotRunOnPhysicalDevice: return "Can't use Snapshot on a physical device." } @@ -75,7 +66,7 @@ open class Snapshot: NSObject { Snapshot.waitForAnimations = waitForAnimations do { - let cacheDir = try pathPrefix() + let cacheDir = try getCacheDirectory() Snapshot.cacheDirectory = cacheDir setLanguage(app) setLocale(app) @@ -206,40 +197,28 @@ open class Snapshot: NSObject { _ = XCTWaiter.wait(for: [networkLoadingIndicatorDisappeared], timeout: timeout) } - class func pathPrefix() throws -> URL? { - let homeDir: URL + class func getCacheDirectory() throws -> URL { + let cachePath = "Library/Caches/tools.fastlane" // on OSX config is stored in /Users//Library // and on iOS/tvOS/WatchOS it's in simulator's home dir #if os(OSX) - guard let user = ProcessInfo().environment["USER"] else { - throw SnapshotError.cannotDetectUser + let homeDir = URL(fileURLWithPath: NSHomeDirectory()) + return homeDir.appendingPathComponent(cachePath) + #elseif arch(i386) || arch(x86_64) + guard let simulatorHostHome = ProcessInfo().environment["SIMULATOR_HOST_HOME"] else { + throw SnapshotError.cannotFindSimulatorHomeDirectory } - - guard let usersDir = FileManager.default.urls(for: .userDirectory, in: .localDomainMask).first else { - throw SnapshotError.cannotFindHomeDirectory - } - - homeDir = usersDir.appendingPathComponent(user) + let homeDir = URL(fileURLWithPath: simulatorHostHome) + return homeDir.appendingPathComponent(cachePath) #else - #if arch(i386) || arch(x86_64) - guard let simulatorHostHome = ProcessInfo().environment["SIMULATOR_HOST_HOME"] else { - throw SnapshotError.cannotFindSimulatorHomeDirectory - } - guard let homeDirUrl = URL(string: simulatorHostHome) else { - throw SnapshotError.cannotAccessSimulatorHomeDirectory(simulatorHostHome) - } - homeDir = URL(fileURLWithPath: homeDirUrl.path) - #else - throw SnapshotError.cannotRunOnPhysicalDevice - #endif + throw SnapshotError.cannotRunOnPhysicalDevice #endif - return homeDir.appendingPathComponent("Library/Caches/tools.fastlane") } } private extension XCUIElementAttributes { var isNetworkLoadingIndicator: Bool { - if hasWhiteListedIdentifier { return false } + if hasAllowListedIdentifier { return false } let hasOldLoadingIndicatorSize = frame.size == CGSize(width: 10, height: 20) let hasNewLoadingIndicatorSize = frame.size.width.isBetween(46, and: 47) && frame.size.height.isBetween(2, and: 3) @@ -247,10 +226,10 @@ private extension XCUIElementAttributes { return hasOldLoadingIndicatorSize || hasNewLoadingIndicatorSize } - var hasWhiteListedIdentifier: Bool { - let whiteListedIdentifiers = ["GeofenceLocationTrackingOn", "StandardLocationTrackingOn"] + var hasAllowListedIdentifier: Bool { + let allowListedIdentifiers = ["GeofenceLocationTrackingOn", "StandardLocationTrackingOn"] - return whiteListedIdentifiers.contains(identifier) + return allowListedIdentifiers.contains(identifier) } func isStatusBar(_ deviceWidth: CGFloat) -> Bool { @@ -300,4 +279,4 @@ private extension CGFloat { // Please don't remove the lines below // They are used to detect outdated configuration files -// SnapshotHelperVersion [1.211] +// SnapshotHelperVersion [1.23] diff --git a/WikiRaces/WikiRacesScreenshots/WikiRacesScreenshots.swift b/WikiRaces/WikiRacesScreenshots/WikiRacesScreenshots.swift index 2a59e2e..e1018d6 100644 --- a/WikiRaces/WikiRacesScreenshots/WikiRacesScreenshots.swift +++ b/WikiRaces/WikiRacesScreenshots/WikiRacesScreenshots.swift @@ -9,29 +9,33 @@ import XCTest class WikiRacesScreenshots: XCTestCase { - + + let app = XCUIApplication() + override func setUp() { super.setUp() continueAfterFailure = false - - let app = XCUIApplication() + setupSnapshot(app) app.launch() } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - - super.tearDown() - } - + func testExample() { + let prefix = "2_DARK" sleep(2) XCUIDevice.shared.orientation = .landscapeLeft - snapshot("1_portrait") - XCUIApplication().buttons["GLOBAL RACE"].tap() - sleep(5) - snapshot("2_game") + snapshot(prefix + "_1_menu") + + app.buttons["CREATE"].tap() + sleep(1) + snapshot(prefix + "_2_host") + + app.buttons["play.fill"].tap() + sleep(6) + snapshot(prefix + "_3_voting") + + sleep(12) + snapshot(prefix + "_4_game") } - + } diff --git a/WikiRaces/fastlane/Deliverfile b/WikiRaces/fastlane/Deliverfile index c345548..2932673 100644 --- a/WikiRaces/fastlane/Deliverfile +++ b/WikiRaces/fastlane/Deliverfile @@ -10,5 +10,5 @@ app_identifier "com.andrewfinke.wikiraces" # The bundle identifier of your app skip_binary_upload true skip_metadata true skip_app_version_update true -overwrite_screenshots true +overwrite_screenshots false run_precheck_before_submit false diff --git a/WikiRaces/fastlane/Snapfile b/WikiRaces/fastlane/Snapfile index 1696981..a28e251 100644 --- a/WikiRaces/fastlane/Snapfile +++ b/WikiRaces/fastlane/Snapfile @@ -2,16 +2,26 @@ # A list of devices you want to take the screenshots from devices([ -"iPad Pro", +"iPad Pro (12.9-inch) (4th generation)", +"iPhone 11 Pro Max", +"iPhone 8 Plus", ]) languages([ - "en-US" +"en-US", + "nl-NL", +"fr-FR", +"de-DE", +"ja", +"ru", +"es-ES", ]) scheme "WikiRacesScreenshots" -dark_mode false +override_status_bar true + +dark_mode true clear_previous_screenshots false