/// Last successful fetch completion time.
-@property(nonatomic, readonly, strong, nullable) NSDate *lastFetchTime;
+@property(nonatomic, readwrite, strong, nullable) NSDate *lastFetchTime;
/// Last fetch status. The status can be any enumerated value from FIRRemoteConfigFetchStatus.
@property(nonatomic, readonly, assign) FIRRemoteConfigFetchStatus lastFetchStatus;
/// Config settings are custom settings.
@property(nonatomic, readwrite, strong, nonnull) FIRRemoteConfigSettings *configSettings;
-/// Returns the FIRRemoteConfig instance shared throughout your app. This singleton object contains
-/// the complete set of Remote Config parameter values available to the app, including the Active
-/// Config and Default Config. This object also caches values fetched from the Remote Config Server
-/// until they are copied to the Active Config by calling activateFetched.
-/// When you fetch values from the Remote Config Server using the default Firebase namespace
-/// service, you should use this class method to create a shared instance of the FIRRemoteConfig
-/// object to ensure that your app will function properly with the Remote Config Server and the
-/// Firebase service.
+/// Returns the FIRRemoteConfig instance configured for the default Firebase app. This singleton
+/// object contains the complete set of Remote Config parameter values available to the app,
+/// including the Active Config and Default Config. This object also caches values fetched from the
+/// Remote Config Server until they are copied to the Active Config by calling activateFetched. When
+/// you fetch values from the Remote Config Server using the default Firebase namespace service, you
+/// should use this class method to create a shared instance of the FIRRemoteConfig object to ensure
+/// that your app will function properly with the Remote Config Server and the Firebase service.
+ (nonnull FIRRemoteConfig *)remoteConfig NS_SWIFT_NAME(remoteConfig());
+/// Returns the FIRRemoteConfig instance for your (non-default) Firebase appID. Note that Firebase
+/// analytics does not work for non-default app instances. This singleton object contains the
+/// complete set of Remote Config parameter values available to the app, including the Active Config
+/// and Default Config. This object also caches values fetched from the Remote Config Server until
+/// they are copied to the Active Config by calling activateFetched. When you fetch values from the
+/// Remote Config Server using the default Firebase namespace service, you should use this class
+/// method to create a shared instance of the FIRRemoteConfig object to ensure that your app will
+/// function properly with the Remote Config Server and the Firebase service.
++ (nonnull FIRRemoteConfig *)remoteConfigWithApp:(nonnull FIRApp *)app
+ NS_SWIFT_NAME(remoteConfig(app:));
+
/// Unavailable. Use +remoteConfig instead.
- (nonnull instancetype)init __attribute__((unavailable("Use +remoteConfig instead.")));
+/// Ensures initialization is complete and clients can begin querying for Remote Config values.
+/// @param completionHandler Initialization complete callback.
+- (void)ensureInitializedWithCompletionHandler:
+ (nonnull FIRRemoteConfigInitializationCompletion)completionHandler;
#pragma mark - Fetch
/// Fetches Remote Config data with a callback. Call activateFetched to make fetched data available
/// to your app.
@@ -135,22 +210,43 @@ NS_SWIFT_NAME(RemoteConfig)
/// To stop the periodic sync, developers need to call `[FIRInstanceID deleteIDWithHandler:]` and
/// avoid calling this method again.
///
-/// @param expirationDuration Duration that defines how long fetched config data is available, in
-/// seconds. When the config data expires, a new fetch is required.
+/// @param expirationDuration Override the (default or optionally set minimumFetchInterval property
+/// in FIRRemoteConfigSettings) minimumFetchInterval for only the current request, in seconds.
+/// Setting a value of 0 seconds will force a fetch to the backend.
/// @param completionHandler Fetch operation callback.
- (void)fetchWithExpirationDuration:(NSTimeInterval)expirationDuration
completionHandler:(nullable FIRRemoteConfigFetchCompletion)completionHandler;
+/// Fetches Remote Config data and if successful, activates fetched data. Optional completion
+/// handler callback is invoked after the attempted activation of data, if the fetch call succeeded.
+///
+/// Note: This method uses a Firebase Instance ID token to identify the app instance, and once it's
+/// called, it periodically sends data to the Firebase backend. (see
+/// `[FIRInstanceID getIDWithHandler:]`).
+/// To stop the periodic sync, developers need to call `[FIRInstanceID deleteIDWithHandler:]` and
+/// avoid calling this method again.
+///
+/// @param completionHandler Fetch operation callback.
+- (void)fetchAndActivateWithCompletionHandler:
+ (nullable FIRRemoteConfigFetchAndActivateCompletion)completionHandler;
+
#pragma mark - Apply
+
+/// Applies Fetched Config data to the Active Config, causing updates to the behavior and appearance
+/// of the app to take effect (depending on how config data is used in the app).
+/// @param completionHandler Activate operation callback.
+- (void)activateWithCompletionHandler:(nullable FIRRemoteConfigActivateCompletion)completionHandler;
+
+/// This method is deprecated. Please use -[FIRRemoteConfig activateWithCompletionHandler:] instead.
/// Applies Fetched Config data to the Active Config, causing updates to the behavior and appearance
/// of the app to take effect (depending on how config data is used in the app).
/// Returns true if there was a Fetched Config, and it was activated.
/// Returns false if no Fetched Config was found, or the Fetched Config was already activated.
-- (BOOL)activateFetched;
+- (BOOL)activateFetched DEPRECATED_MSG_ATTRIBUTE("Use -[FIRRemoteConfig activate] "
+ "instead.");
#pragma mark - Get Config
/// Enables access to configuration values by using object subscripting syntax.
-/// This is used to get the config value of the default namespace.
///
/// // Example:
/// FIRRemoteConfig *config = [FIRRemoteConfig remoteConfig];
@@ -160,7 +256,7 @@ NS_SWIFT_NAME(RemoteConfig)
///
- (nonnull FIRRemoteConfigValue *)objectForKeyedSubscript:(nonnull NSString *)key;
-/// Gets the config value of the default namespace.
+/// Gets the config value.
/// @param key Config key.
- (nonnull FIRRemoteConfigValue *)configValueForKey:(nullable NSString *)key;
@@ -168,7 +264,15 @@ NS_SWIFT_NAME(RemoteConfig)
/// @param key Config key.
/// @param aNamespace Config results under a given namespace.
- (nonnull FIRRemoteConfigValue *)configValueForKey:(nullable NSString *)key
- namespace:(nullable NSString *)aNamespace;
+ namespace:(nullable NSString *)aNamespace
+ DEPRECATED_MSG_ATTRIBUTE("Use -[FIRRemoteConfig configValueForKey:] "
+ "instead.");
+
+/// Gets the config value of a given namespace and a given source.
+/// @param key Config key.
+/// @param source Config value source.
+- (nonnull FIRRemoteConfigValue *)configValueForKey:(nullable NSString *)key
+ source:(FIRRemoteConfigSource)source;
/// Gets the config value of a given namespace and a given source.
/// @param key Config key.
@@ -176,7 +280,15 @@ NS_SWIFT_NAME(RemoteConfig)
/// @param source Config value source.
- (nonnull FIRRemoteConfigValue *)configValueForKey:(nullable NSString *)key
namespace:(nullable NSString *)aNamespace
- source:(FIRRemoteConfigSource)source;
+ source:(FIRRemoteConfigSource)source
+ DEPRECATED_MSG_ATTRIBUTE("Use -[FIRRemoteConfig configValueForKey:source:] "
+ "instead.");
+
+/// Gets all the parameter keys from a given source and a given namespace.
+///
+/// @param source The config data source.
+/// @return An array of keys under the given source and namespace.
+- (nonnull NSArray *)allKeysFromSource:(FIRRemoteConfigSource)source;
/// Gets all the parameter keys from a given source and a given namespace.
///
@@ -184,7 +296,8 @@ NS_SWIFT_NAME(RemoteConfig)
/// @param aNamespace The config data namespace.
/// @return An array of keys under the given source and namespace.
- (nonnull NSArray *)allKeysFromSource:(FIRRemoteConfigSource)source
- namespace:(nullable NSString *)aNamespace;
+ namespace:(nullable NSString *)aNamespace
+ DEPRECATED_MSG_ATTRIBUTE("Use -[FIRRemoteConfig allKeysFromSource:] instead.");
/// Returns the set of parameter keys that start with the given prefix, from the default namespace
/// in the active config.
@@ -203,11 +316,11 @@ NS_SWIFT_NAME(RemoteConfig)
/// returns an empty set.
/// @return The set of parameter keys that start with the specified prefix.
- (nonnull NSSet *)keysWithPrefix:(nullable NSString *)prefix
- namespace:(nullable NSString *)aNamespace;
+ namespace:(nullable NSString *)aNamespace
+ DEPRECATED_MSG_ATTRIBUTE("Use -[FIRRemoteConfig keysWithPrefix:] instead.");
#pragma mark - Defaults
/// Sets config defaults for parameter keys and values in the default namespace config.
-///
/// @param defaults A dictionary mapping a NSString * key to a NSObject * value.
- (void)setDefaults:(nullable NSDictionary *)defaults;
@@ -216,7 +329,8 @@ NS_SWIFT_NAME(RemoteConfig)
/// @param defaults A dictionary mapping a NSString * key to a NSObject * value.
/// @param aNamespace Config under a given namespace.
- (void)setDefaults:(nullable NSDictionary *)defaults
- namespace:(nullable NSString *)aNamespace;
+ namespace:(nullable NSString *)aNamespace
+ DEPRECATED_MSG_ATTRIBUTE("Use -[FIRRemoteConfig setDefaults:] instead.");
/// Sets default configs from plist for default namespace;
/// @param fileName The plist file name, with no file name extension. For example, if the plist file
@@ -232,7 +346,15 @@ NS_SWIFT_NAME(RemoteConfig)
/// @param aNamespace The namespace where the default config is set.
- (void)setDefaultsFromPlistFileName:(nullable NSString *)fileName
namespace:(nullable NSString *)aNamespace
- NS_SWIFT_NAME(setDefaults(fromPlist:namespace:));
+ NS_SWIFT_NAME(setDefaults(fromPlist:namespace:))
+ DEPRECATED_MSG_ATTRIBUTE("Use -[FIRRemoteConfig setDefaultsFromPlistFileName:] instead.");
+
+/// Returns the default value of a given key and a given namespace from the default config.
+///
+/// @param key The parameter key of default config.
+/// @return Returns the default value of the specified key and namespace. Returns
+/// nil if the key or namespace doesn't exist in the default config.
+- (nullable FIRRemoteConfigValue *)defaultValueForKey:(nullable NSString *)key;
/// Returns the default value of a given key and a given namespace from the default config.
///
@@ -241,6 +363,7 @@ NS_SWIFT_NAME(RemoteConfig)
/// @return Returns the default value of the specified key and namespace. Returns
/// nil if the key or namespace doesn't exist in the default config.
- (nullable FIRRemoteConfigValue *)defaultValueForKey:(nullable NSString *)key
- namespace:(nullable NSString *)aNamespace;
+ namespace:(nullable NSString *)aNamespace
+ DEPRECATED_MSG_ATTRIBUTE("Use -[FIRRemoteConfig defaultValueForKey:] instead.");
@end
diff --git a/WikiRaces/Shared/Frameworks/Analytics/FirebaseRemoteConfig.framework/Headers/FirebaseRemoteConfig.h b/WikiRaces/Shared/Frameworks/Analytics/FirebaseRemoteConfig.framework/Headers/FirebaseRemoteConfig.h
old mode 100755
new mode 100644
index eedc4fc..9ae8cea
--- a/WikiRaces/Shared/Frameworks/Analytics/FirebaseRemoteConfig.framework/Headers/FirebaseRemoteConfig.h
+++ b/WikiRaces/Shared/Frameworks/Analytics/FirebaseRemoteConfig.framework/Headers/FirebaseRemoteConfig.h
@@ -1 +1,17 @@
+/*
+ * Copyright 2019 Google
+ *
+ * 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 "FIRRemoteConfig.h"
diff --git a/WikiRaces/Shared/Frameworks/Analytics/FirebaseRemoteConfig.framework/Modules/module.modulemap b/WikiRaces/Shared/Frameworks/Analytics/FirebaseRemoteConfig.framework/Modules/module.modulemap
old mode 100755
new mode 100644
index 018acb5..51eaec0
--- a/WikiRaces/Shared/Frameworks/Analytics/FirebaseRemoteConfig.framework/Modules/module.modulemap
+++ b/WikiRaces/Shared/Frameworks/Analytics/FirebaseRemoteConfig.framework/Modules/module.modulemap
@@ -1,13 +1,5 @@
framework module FirebaseRemoteConfig {
- umbrella header "FirebaseRemoteConfig.h"
- export *
- module * { export * }
- link "sqlite3"
- link "z"
- link framework "CoreFoundation"
- link framework "Foundation"
- link framework "Security"
- link framework "StoreKit"
- link framework "SystemConfiguration"
- link framework "UIKit"
+umbrella header "FirebaseRemoteConfig.h"
+export *
+module * { export * }
}
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GTMSessionFetcher.framework/GTMSessionFetcher b/WikiRaces/Shared/Frameworks/Analytics/GTMSessionFetcher.framework/GTMSessionFetcher
index 3e75324..4ff7511 100644
Binary files a/WikiRaces/Shared/Frameworks/Analytics/GTMSessionFetcher.framework/GTMSessionFetcher and b/WikiRaces/Shared/Frameworks/Analytics/GTMSessionFetcher.framework/GTMSessionFetcher differ
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GTMSessionFetcher.framework/Headers/GTMSessionFetcher.h b/WikiRaces/Shared/Frameworks/Analytics/GTMSessionFetcher.framework/Headers/GTMSessionFetcher.h
index 7f5fcda..73193f6 100644
--- a/WikiRaces/Shared/Frameworks/Analytics/GTMSessionFetcher.framework/Headers/GTMSessionFetcher.h
+++ b/WikiRaces/Shared/Frameworks/Analytics/GTMSessionFetcher.framework/Headers/GTMSessionFetcher.h
@@ -631,7 +631,7 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
- (GTM_NULLABLE NSDate *)stoppedAllFetchersDate;
// Methods for compatibility with the old GTMHTTPFetcher.
-@property(readonly, strong, GTM_NULLABLE) NSOperationQueue *delegateQueue;
+@property(atomic, readonly, strong, GTM_NULLABLE) NSOperationQueue *delegateQueue;
@end // @protocol GTMSessionFetcherServiceProtocol
@@ -653,25 +653,25 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
- (BOOL)isAuthorizedRequest:(NSURLRequest *)request;
-@property(strong, readonly, GTM_NULLABLE) NSString *userEmail;
+@property(atomic, strong, readonly, GTM_NULLABLE) NSString *userEmail;
@optional
// Indicate if authorization may be attempted. Even if this succeeds,
// authorization may fail if the user's permissions have been revoked.
-@property(readonly) BOOL canAuthorize;
+@property(atomic, readonly) BOOL canAuthorize;
// For development only, allow authorization of non-SSL requests, allowing
// transmission of the bearer token unencrypted.
-@property(assign) BOOL shouldAuthorizeAllRequests;
+@property(atomic, assign) BOOL shouldAuthorizeAllRequests;
- (void)authorizeRequest:(GTM_NULLABLE NSMutableURLRequest *)request
completionHandler:(void (^)(NSError * GTM_NULLABLE_TYPE error))handler;
#if GTM_USE_SESSION_FETCHER
-@property (weak, GTM_NULLABLE) id fetcherService;
+@property(atomic, weak, GTM_NULLABLE) id fetcherService;
#else
-@property (weak, GTM_NULLABLE) id fetcherService;
+@property(atomic, weak, GTM_NULLABLE) id fetcherService;
#endif
- (BOOL)primeForRefresh;
@@ -728,7 +728,7 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
// The fetcher's request. This may not be set after beginFetch has been invoked. The request
// may change due to redirects.
-@property(strong, GTM_NULLABLE) NSURLRequest *request;
+@property(atomic, strong, GTM_NULLABLE) NSURLRequest *request;
// Set a header field value on the request. Header field value changes will not
// affect a fetch after the fetch has begun.
@@ -819,7 +819,7 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
// "Background Session Task state persistence"
// https://forums.developer.apple.com/thread/11554
//
-@property(assign) BOOL useBackgroundSession;
+@property(atomic, assign) BOOL useBackgroundSession;
// Indicates if the fetcher was started using a background session.
@property(atomic, readonly, getter=isUsingBackgroundSession) BOOL usingBackgroundSession;
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleAppMeasurement.framework/GoogleAppMeasurement b/WikiRaces/Shared/Frameworks/Analytics/GoogleAppMeasurement.framework/GoogleAppMeasurement
index 2561d1a..375453c 100755
Binary files a/WikiRaces/Shared/Frameworks/Analytics/GoogleAppMeasurement.framework/GoogleAppMeasurement and b/WikiRaces/Shared/Frameworks/Analytics/GoogleAppMeasurement.framework/GoogleAppMeasurement differ
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleAppMeasurement.framework/Modules/module.modulemap b/WikiRaces/Shared/Frameworks/Analytics/GoogleAppMeasurement.framework/Modules/module.modulemap
index b66fb64..de80e9e 100755
--- a/WikiRaces/Shared/Frameworks/Analytics/GoogleAppMeasurement.framework/Modules/module.modulemap
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleAppMeasurement.framework/Modules/module.modulemap
@@ -3,6 +3,7 @@ framework module GoogleAppMeasurement {
module * { export * }
link "sqlite3"
link "z"
+ link framework "CoreData"
link framework "Security"
link framework "StoreKit"
link framework "SystemConfiguration"
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/GoogleDataTransport b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/GoogleDataTransport
new file mode 100644
index 0000000..db493ff
Binary files /dev/null and b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/GoogleDataTransport differ
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORAssert.h b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORAssert.h
new file mode 100644
index 0000000..941e412
--- /dev/null
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORAssert.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2019 Google
+ *
+ * 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
+
+#import
+
+/** A block type that could be run instead of normal assertion logging. No return type, no params.
+ */
+typedef void (^GDTCORAssertionBlock)(void);
+
+/** Returns the result of executing a soft-linked method present in unit tests that allows a block
+ * to be run instead of normal assertion logging. This helps ameliorate issues with catching
+ * exceptions that occur on a dispatch_queue.
+ *
+ * @return A block that can be run instead of normal assert printing.
+ */
+FOUNDATION_EXPORT GDTCORAssertionBlock _Nullable GDTCORAssertionBlockToRunInstead(void);
+
+#if defined(NS_BLOCK_ASSERTIONS)
+
+#define GDTCORAssert(condition, ...) \
+ do { \
+ } while (0);
+
+#define GDTCORFatalAssert(condition, ...) \
+ do { \
+ } while (0);
+
+#else // defined(NS_BLOCK_ASSERTIONS)
+
+/** Asserts using a console log, unless a block was specified to be run instead.
+ *
+ * @param condition The condition you'd expect to be YES.
+ */
+#define GDTCORAssert(condition, ...) \
+ do { \
+ if (__builtin_expect(!(condition), 0)) { \
+ GDTCORAssertionBlock assertionBlock = GDTCORAssertionBlockToRunInstead(); \
+ if (assertionBlock) { \
+ assertionBlock(); \
+ } else { \
+ __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \
+ NSString *__assert_file__ = [NSString stringWithUTF8String:__FILE__]; \
+ __assert_file__ = __assert_file__ ? __assert_file__ : @""; \
+ GDTCORLogError(GDTCORMCEGeneralError, @"Assertion failed (%@:%d): %s,", __assert_file__, \
+ __LINE__, ##__VA_ARGS__); \
+ __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \
+ } \
+ } \
+ } while (0);
+
+/** Asserts by logging to the console and throwing an exception if NS_BLOCK_ASSERTIONS is not
+ * defined.
+ *
+ * @param condition The condition you'd expect to be YES.
+ */
+#define GDTCORFatalAssert(condition, ...) \
+ do { \
+ __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \
+ if (__builtin_expect(!(condition), 0)) { \
+ NSString *__assert_file__ = [NSString stringWithUTF8String:__FILE__]; \
+ __assert_file__ = __assert_file__ ? __assert_file__ : @""; \
+ GDTCORLogError(GDTCORMCEFatalAssertion, \
+ @"Fatal assertion encountered, please open an issue at " \
+ "https://github.com/firebase/firebase-ios-sdk/issues " \
+ "(%@:%d): %s,", \
+ __assert_file__, __LINE__, ##__VA_ARGS__); \
+ [[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd \
+ object:self \
+ file:__assert_file__ \
+ lineNumber:__LINE__ \
+ description:@"%@", ##__VA_ARGS__]; \
+ } \
+ __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \
+ } while (0);
+
+#endif // defined(NS_BLOCK_ASSERTIONS)
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORClock.h b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORClock.h
new file mode 100644
index 0000000..01de21a
--- /dev/null
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORClock.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018 Google
+ *
+ * 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
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** This class manages the device clock and produces snapshots of the current time. */
+@interface GDTCORClock : NSObject
+
+/** The wallclock time, UTC, in milliseconds. */
+@property(nonatomic, readonly) int64_t timeMillis;
+
+/** The offset from UTC in seconds. */
+@property(nonatomic, readonly) int64_t timezoneOffsetSeconds;
+
+/** The kernel boot time when this clock was created. */
+@property(nonatomic, readonly) int64_t kernelBootTime;
+
+/** The device uptime when this clock was created. */
+@property(nonatomic, readonly) int64_t uptime;
+
+/** Creates a GDTCORClock object using the current time and offsets.
+ *
+ * @return A new GDTCORClock object representing the current time state.
+ */
++ (instancetype)snapshot;
+
+/** Creates a GDTCORClock object representing a time in the future, relative to now.
+ *
+ * @param millisInTheFuture The millis in the future from now this clock should represent.
+ * @return An instance representing a future time.
+ */
++ (instancetype)clockSnapshotInTheFuture:(uint64_t)millisInTheFuture;
+
+/** Compares one clock with another, returns YES if the caller is after the parameter.
+ *
+ * @return YES if the calling clock's time is after the given clock's time.
+ */
+- (BOOL)isAfter:(GDTCORClock *)otherClock;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORConsoleLogger.h b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORConsoleLogger.h
new file mode 100644
index 0000000..b7e7818
--- /dev/null
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORConsoleLogger.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2018 Google
+ *
+ * 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
+
+/** A list of message codes to print in the logger that help to correspond printed messages with
+ * code locations.
+ *
+ * Prefixes:
+ * - MCW => MessageCodeWarning
+ * - MCE => MessageCodeError
+ */
+typedef NS_ENUM(NSInteger, GDTCORMessageCode) {
+
+ /** For warning messages concerning transportBytes: not being implemented by a data object. */
+ GDTCORMCWDataObjectMissingBytesImpl = 1,
+
+ /** For warning messages concerning a failed event upload. */
+ GDTCORMCWUploadFailed = 2,
+
+ /** For warning messages concerning a forced event upload. */
+ GDTCORMCWForcedUpload = 3,
+
+ /** For warning messages concerning a failed reachability call. */
+ GDTCORMCWReachabilityFailed = 4,
+
+ /** For error messages concerning transform: not being implemented by an event transformer. */
+ GDTCORMCETransformerDoesntImplementTransform = 1000,
+
+ /** For error messages concerning the creation of a directory failing. */
+ GDTCORMCEDirectoryCreationError = 1001,
+
+ /** For error messages concerning the writing of a event file. */
+ GDTCORMCEFileWriteError = 1002,
+
+ /** For error messages concerning the lack of a prioritizer for a given backend. */
+ GDTCORMCEPrioritizerError = 1003,
+
+ /** For error messages concerning a package delivery API violation. */
+ GDTCORMCEDeliverTwice = 1004,
+
+ /** For error messages concerning an error in an implementation of -transportBytes. */
+ GDTCORMCETransportBytesError = 1005,
+
+ /** For general purpose error messages in a dependency. */
+ GDTCORMCEGeneralError = 1006,
+
+ /** For fatal errors. Please go to https://github.com/firebase/firebase-ios-sdk/issues and open
+ * an issue if you encounter an error with this code.
+ */
+ GDTCORMCEFatalAssertion = 1007
+};
+
+/** */
+FOUNDATION_EXPORT
+void GDTCORLog(GDTCORMessageCode code, NSString *_Nonnull format, ...);
+
+/** Returns the string that represents some message code.
+ *
+ * @param code The code to convert to a string.
+ * @return The string representing the message code.
+ */
+FOUNDATION_EXPORT NSString *_Nonnull GDTCORMessageCodeEnumToString(GDTCORMessageCode code);
+
+// A define to wrap GULLogWarning with slightly more convenient usage.
+#define GDTCORLogWarning(MESSAGE_CODE, MESSAGE_FORMAT, ...) \
+ GDTCORLog(MESSAGE_CODE, MESSAGE_FORMAT, __VA_ARGS__);
+
+// A define to wrap GULLogError with slightly more convenient usage and a failing assert.
+#define GDTCORLogError(MESSAGE_CODE, MESSAGE_FORMAT, ...) \
+ GDTCORLog(MESSAGE_CODE, MESSAGE_FORMAT, __VA_ARGS__);
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORDataFuture.h b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORDataFuture.h
new file mode 100644
index 0000000..07f428f
--- /dev/null
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORDataFuture.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 Google
+ *
+ * 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
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** This class represents a future data object, determined at instantiation time. */
+@interface GDTCORDataFuture : NSObject
+
+/** The data, computed on-demand, depending on the initializer. */
+@property(nullable, readonly, nonatomic) NSData *data;
+
+/** If not nil, this data future was instantiated with this file URL. */
+@property(nullable, readonly, nonatomic) NSURL *fileURL;
+
+/** If not nil, this data future was instantiated with this NSData instance. */
+@property(nullable, readonly, nonatomic) NSData *originalData;
+
+/** Initializes an instance with the given the fileURL.
+ *
+ * @param fileURL The fileURL containing the data to return in -data.
+ * @return An instance of this class.
+ */
+- (instancetype)initWithFileURL:(NSURL *)fileURL;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCOREvent.h b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCOREvent.h
new file mode 100644
index 0000000..1ab55de
--- /dev/null
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCOREvent.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2018 Google
+ *
+ * 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
+
+#import
+
+@class GDTCORClock;
+@class GDTCORDataFuture;
+@class GDTCORStoredEvent;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** The different possible quality of service specifiers. High values indicate high priority. */
+typedef NS_ENUM(NSInteger, GDTCOREventQoS) {
+ /** The QoS tier wasn't set, and won't ever be sent. */
+ GDTCOREventQoSUnknown = 0,
+
+ /** This event is internal telemetry data that should not be sent on its own if possible. */
+ GDTCOREventQoSTelemetry = 1,
+
+ /** This event should be sent, but in a batch only roughly once per day. */
+ GDTCOREventQoSDaily = 2,
+
+ /** This event should be sent when requested by the uploader. */
+ GDTCOREventQosDefault = 3,
+
+ /** This event should be sent immediately along with any other data that can be batched. */
+ GDTCOREventQoSFast = 4,
+
+ /** This event should only be uploaded on wifi. */
+ GDTCOREventQoSWifiOnly = 5,
+};
+
+@interface GDTCOREvent : NSObject
+
+/** The mapping identifier, to allow backends to map the transport bytes to a proto. */
+@property(readonly, nonatomic) NSString *mappingID;
+
+/** The identifier for the backend this event will eventually be sent to. */
+@property(readonly, nonatomic) NSInteger target;
+
+/** The data object encapsulated in the transport of your choice, as long as it implements
+ * the GDTCOREventDataObject protocol. */
+@property(nullable, nonatomic) id dataObject;
+
+/** The quality of service tier this event belongs to. */
+@property(nonatomic) GDTCOREventQoS qosTier;
+
+/** The clock snapshot at the time of the event. */
+@property(nonatomic) GDTCORClock *clockSnapshot;
+
+/** A dictionary provided to aid prioritizers by allowing the passing of arbitrary data. It will be
+ * retained by a copy in -copy, but not used for -hash.
+ *
+ * @note Ensure that classes contained therein implement NSSecureCoding to prevent loss of data.
+ */
+@property(nullable, nonatomic) NSDictionary *customPrioritizationParams;
+
+// Please use the designated initializer.
+- (instancetype)init NS_UNAVAILABLE;
+
+/** Initializes an instance using the given mappingID.
+ *
+ * @param mappingID The mapping identifier.
+ * @param target The event's target identifier.
+ * @return An instance of this class.
+ */
+- (nullable instancetype)initWithMappingID:(NSString *)mappingID
+ target:(NSInteger)target NS_DESIGNATED_INITIALIZER;
+
+/** Returns the GDTCORStoredEvent equivalent of self.
+ *
+ * @param dataFuture The data future representing the transport bytes of the original event.
+ * @return An equivalent GDTCORStoredEvent.
+ */
+- (GDTCORStoredEvent *)storedEventWithDataFuture:(GDTCORDataFuture *)dataFuture;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCOREventDataObject.h b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCOREventDataObject.h
new file mode 100644
index 0000000..34ef624
--- /dev/null
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCOREventDataObject.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2018 Google
+ *
+ * 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
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** This protocol defines the common interface that event protos should implement regardless of the
+ * underlying transport technology (protobuf, nanopb, etc).
+ */
+@protocol GDTCOREventDataObject
+
+@required
+
+/** Returns the serialized proto bytes of the implementing event proto.
+ *
+ * @return the serialized proto bytes of the implementing event proto.
+ */
+- (NSData *)transportBytes;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCOREventTransformer.h b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCOREventTransformer.h
new file mode 100644
index 0000000..c26d0c2
--- /dev/null
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCOREventTransformer.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2018 Google
+ *
+ * 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
+
+@class GDTCOREvent;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** Defines the API that event transformers must adopt. */
+@protocol GDTCOREventTransformer
+
+@required
+
+/** Transforms an event by applying some logic to it. Events returned can be nil, for example, in
+ * instances where the event should be sampled.
+ *
+ * @param event The event to transform.
+ * @return A transformed event, or nil if the transformation dropped the event.
+ */
+- (GDTCOREvent *)transform:(GDTCOREvent *)event;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORLifecycle.h b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORLifecycle.h
new file mode 100644
index 0000000..4d61a21
--- /dev/null
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORLifecycle.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2019 Google
+ *
+ * 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
+
+#import
+
+@class GDTCOREvent;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** A protocol defining the lifecycle events objects in the library must respond to immediately. */
+@protocol GDTCORLifecycleProtocol
+
+@optional
+
+/** Indicates an imminent app termination in the rare occurrence when -applicationWillTerminate: has
+ * been called.
+ *
+ * @param app The GDTCORApplication instance.
+ */
+- (void)appWillTerminate:(GDTCORApplication *)app;
+
+/** Indicates that the app is moving to background and eventual suspension or the current UIScene is
+ * deactivating.
+ *
+ * @param app The GDTCORApplication instance.
+ */
+- (void)appWillBackground:(GDTCORApplication *)app;
+
+/** Indicates that the app is resuming operation or a UIScene is activating.
+ *
+ * @param app The GDTCORApplication instance.
+ */
+- (void)appWillForeground:(GDTCORApplication *)app;
+
+@end
+
+/** This class manages the library's response to app lifecycle events.
+ *
+ * When backgrounding, the library doesn't stop processing events, it's just that several background
+ * tasks will end up being created for every event that's sent, and the stateful objects of the
+ * library (GDTCORStorage and GDTCORUploadCoordinator singletons) will deserialize themselves from
+ * and to disk before and after every operation, respectively.
+ */
+@interface GDTCORLifecycle : NSObject
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORPlatform.h b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORPlatform.h
new file mode 100644
index 0000000..00cafc8
--- /dev/null
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORPlatform.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2019 Google
+ *
+ * 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
+#import
+
+#if TARGET_OS_IOS || TARGET_OS_TV
+#import
+#elif TARGET_OS_OSX
+#import
+#endif // TARGET_OS_IOS || TARGET_OS_TV
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** A notification sent out if the app is backgrounding. */
+FOUNDATION_EXPORT NSString *const kGDTCORApplicationDidEnterBackgroundNotification;
+
+/** A notification sent out if the app is foregrounding. */
+FOUNDATION_EXPORT NSString *const kGDTCORApplicationWillEnterForegroundNotification;
+
+/** A notification sent out if the app is terminating. */
+FOUNDATION_EXPORT NSString *const kGDTCORApplicationWillTerminateNotification;
+
+/** Compares flags with the WWAN reachability flag, if available, and returns YES if present.
+ *
+ * @param flags The set of reachability flags.
+ * @return YES if the WWAN flag is set, NO otherwise.
+ */
+BOOL GDTCORReachabilityFlagsContainWWAN(SCNetworkReachabilityFlags flags);
+
+/** A typedef identify background identifiers. */
+typedef volatile NSUInteger GDTCORBackgroundIdentifier;
+
+/** A background task's invalid sentinel value. */
+FOUNDATION_EXPORT const GDTCORBackgroundIdentifier GDTCORBackgroundIdentifierInvalid;
+
+#if TARGET_OS_IOS || TARGET_OS_TV
+/** A protocol that wraps UIApplicationDelegate or NSObject protocol, depending on the platform. */
+@protocol GDTCORApplicationDelegate
+#elif TARGET_OS_OSX
+@protocol GDTCORApplicationDelegate
+#else
+@protocol GDTCORApplicationDelegate
+#endif // TARGET_OS_IOS || TARGET_OS_TV
+
+@end
+
+/** A cross-platform application class. */
+@interface GDTCORApplication : NSObject
+
+/** Flag to determine if the application is running in the background. */
+@property(atomic, readonly) BOOL isRunningInBackground;
+
+/** Creates and/or returns the shared application instance.
+ *
+ * @return The shared application instance.
+ */
++ (nullable GDTCORApplication *)sharedApplication;
+
+/** Creates a background task with the returned identifier if on a suitable platform.
+ *
+ * @name name The name of the task, useful for debugging which background tasks are running.
+ * @param handler The handler block that is called if the background task expires.
+ * @return An identifier for the background task, or GDTCORBackgroundIdentifierInvalid if one
+ * couldn't be created.
+ */
+- (GDTCORBackgroundIdentifier)beginBackgroundTaskWithName:(NSString *)name
+ expirationHandler:(void (^__nullable)(void))handler;
+
+/** Ends the background task if the identifier is valid.
+ *
+ * @param bgID The background task to end.
+ */
+- (void)endBackgroundTask:(GDTCORBackgroundIdentifier)bgID;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORPrioritizer.h b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORPrioritizer.h
new file mode 100644
index 0000000..3c0c3c6
--- /dev/null
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORPrioritizer.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2018 Google
+ *
+ * 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
+
+#import
+#import
+
+@class GDTCORStoredEvent;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** Options that define a set of upload conditions. This is used to help minimize end user data
+ * consumption impact.
+ */
+typedef NS_OPTIONS(NSInteger, GDTCORUploadConditions) {
+
+ /** An upload shouldn't be attempted, because there's no network. */
+ GDTCORUploadConditionNoNetwork = 1 << 0,
+
+ /** An upload would likely use mobile data. */
+ GDTCORUploadConditionMobileData = 1 << 1,
+
+ /** An upload would likely use wifi data. */
+ GDTCORUploadConditionWifiData = 1 << 2,
+
+ /** An upload uses some sort of network connection, but it's unclear which. */
+ GDTCORUploadConditionUnclearConnection = 1 << 3,
+
+ /** A high priority event has occurred. */
+ GDTCORUploadConditionHighPriority = 1 << 4,
+};
+
+/** This protocol defines the common interface of event prioritization. Prioritizers are
+ * stateful objects that prioritize events upon insertion into storage and remain prepared to return
+ * a set of filenames to the storage system.
+ */
+@protocol GDTCORPrioritizer
+
+@required
+
+/** Accepts an event and uses the event metadata to make choices on how to prioritize the event.
+ * This method exists as a way to help prioritize which events should be sent, which is dependent on
+ * the request proto structure of your backend.
+ *
+ * @param event The event to prioritize.
+ */
+- (void)prioritizeEvent:(GDTCORStoredEvent *)event;
+
+/** Returns a set of events to upload given a set of conditions.
+ *
+ * @param conditions A bit mask specifying the current upload conditions.
+ * @return An object to be used by the uploader to determine file URLs to upload with respect to the
+ * current conditions.
+ */
+- (GDTCORUploadPackage *)uploadPackageWithConditions:(GDTCORUploadConditions)conditions;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORRegistrar.h b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORRegistrar.h
new file mode 100644
index 0000000..0a8fbb0
--- /dev/null
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORRegistrar.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 Google
+ *
+ * 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
+
+#import
+#import
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** Manages the registration of targets with the transport SDK. */
+@interface GDTCORRegistrar : NSObject
+
+/** Creates and/or returns the singleton instance.
+ *
+ * @return The singleton instance of this class.
+ */
++ (instancetype)sharedInstance;
+
+/** Registers a backend implementation with the GoogleDataTransport infrastructure.
+ *
+ * @param backend The backend object to register.
+ * @param target The target this backend object will be responsible for.
+ */
+- (void)registerUploader:(id)backend target:(GDTCORTarget)target;
+
+/** Registers a event prioritizer implementation with the GoogleDataTransport infrastructure.
+ *
+ * @param prioritizer The prioritizer object to register.
+ * @param target The target this prioritizer object will be responsible for.
+ */
+- (void)registerPrioritizer:(id)prioritizer target:(GDTCORTarget)target;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORStoredEvent.h b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORStoredEvent.h
new file mode 100644
index 0000000..647b220
--- /dev/null
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORStoredEvent.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2019 Google
+ *
+ * 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
+
+#import
+#import
+
+@class GDTCOREvent;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface GDTCORStoredEvent : NSObject
+
+/** The data future representing the original event's transport bytes. */
+@property(readonly, nonatomic) GDTCORDataFuture *dataFuture;
+
+/** The mapping identifier, to allow backends to map the transport bytes to a proto. */
+@property(readonly, nonatomic) NSString *mappingID;
+
+/** The identifier for the backend this event will eventually be sent to. */
+@property(readonly, nonatomic) NSNumber *target;
+
+/** The quality of service tier this event belongs to. */
+@property(readonly, nonatomic) GDTCOREventQoS qosTier;
+
+/** The clock snapshot at the time of the event. */
+@property(readonly, nonatomic) GDTCORClock *clockSnapshot;
+
+/** A dictionary provided to aid prioritizers by allowing the passing of arbitrary data.
+ *
+ * @note Ensure that custom classes in this dict implement NSSecureCoding to prevent loss of data.
+ */
+@property(readonly, nullable, nonatomic) NSDictionary *customPrioritizationParams;
+
+/** Initializes a stored event with the given URL and event.
+ *
+ * @param event The event this stored event represents.
+ * @param dataFuture The dataFuture this event represents.
+ * @return An instance of this class.
+ */
+- (instancetype)initWithEvent:(GDTCOREvent *)event dataFuture:(GDTCORDataFuture *)dataFuture;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORTargets.h b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORTargets.h
new file mode 100644
index 0000000..ebd36d1
--- /dev/null
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORTargets.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019 Google
+ *
+ * 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
+
+/** The list of targets supported by the shared transport infrastructure. If adding a new target,
+ * please use the previous value +1.
+ */
+typedef NS_ENUM(NSInteger, GDTCORTarget) {
+
+ /** A target only used in testing. */
+ kGDTCORTargetTest = 999,
+
+ /** The CCT target. */
+ kGDTCORTargetCCT = 1000,
+
+ /** The FLL target. */
+ kGDTCORTargetFLL = 1001,
+};
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORTransport.h b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORTransport.h
new file mode 100644
index 0000000..a952240
--- /dev/null
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORTransport.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2018 Google
+ *
+ * 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
+
+#import
+
+@class GDTCOREvent;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface GDTCORTransport : NSObject
+
+// Please use the designated initializer.
+- (instancetype)init NS_UNAVAILABLE;
+
+/** Initializes a new transport that will send events to the given target backend.
+ *
+ * @param mappingID The mapping identifier used by the backend to map the data object transport
+ * bytes to a proto.
+ * @param transformers A list of transformers to be applied to events that are sent.
+ * @param target The target backend of this transport.
+ * @return A transport that will send events.
+ */
+- (nullable instancetype)initWithMappingID:(NSString *)mappingID
+ transformers:
+ (nullable NSArray> *)transformers
+ target:(NSInteger)target NS_DESIGNATED_INITIALIZER;
+
+/** Copies and sends an internal telemetry event. Events sent using this API are lower in priority,
+ * and sometimes won't be sent on their own.
+ *
+ * @note This will convert the event's data object to data and release the original event.
+ *
+ * @param event The event to send.
+ */
+- (void)sendTelemetryEvent:(GDTCOREvent *)event;
+
+/** Copies and sends an SDK service data event. Events send using this API are higher in priority,
+ * and will cause a network request at some point in the relative near future.
+ *
+ * @note This will convert the event's data object to data and release the original event.
+ *
+ * @param event The event to send.
+ */
+- (void)sendDataEvent:(GDTCOREvent *)event;
+
+/** Creates an event for use by this transport.
+ *
+ * @return An event that is suited for use by this transport.
+ */
+- (GDTCOREvent *)eventForTransport;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORUploadPackage.h b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORUploadPackage.h
new file mode 100644
index 0000000..46a676b
--- /dev/null
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORUploadPackage.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2019 Google
+ *
+ * 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
+
+#import
+
+@class GDTCORClock;
+@class GDTCORStoredEvent;
+@class GDTCORUploadPackage;
+
+/** A protocol that allows a handler to respond to package lifecycle events. */
+@protocol GDTCORUploadPackageProtocol
+
+@optional
+
+/** Indicates that the package has expired.
+ *
+ * @note Package expiration will only be checked every 5 seconds.
+ *
+ * @param package The package that has expired.
+ */
+- (void)packageExpired:(GDTCORUploadPackage *)package;
+
+/** Indicates that the package was successfully delivered.
+ *
+ * @param package The package that was delivered.
+ */
+- (void)packageDelivered:(GDTCORUploadPackage *)package successful:(BOOL)successful;
+
+@end
+
+/** This class is a container that's handed off to uploaders. */
+@interface GDTCORUploadPackage : NSObject
+
+/** The set of stored events in this upload package. */
+@property(nonatomic) NSSet *events;
+
+/** The expiration time. If [[GDTCORClock snapshot] isAfter:deliverByTime] this package has expired.
+ *
+ * @note By default, the expiration time will be 3 minutes from creation.
+ */
+@property(nonatomic) GDTCORClock *deliverByTime;
+
+/** The target of this package. */
+@property(nonatomic, readonly) GDTCORTarget target;
+
+/** Initializes a package instance.
+ *
+ * @param target The target/destination of this package.
+ * @return An instance of this class.
+ */
+- (instancetype)initWithTarget:(GDTCORTarget)target NS_DESIGNATED_INITIALIZER;
+
+// Please use the designated initializer.
+- (instancetype)init NS_UNAVAILABLE;
+
+/** Completes delivery of the package.
+ *
+ * @note This *needs* to be called by an uploader for the package to not expire.
+ */
+- (void)completeDelivery;
+
+/** Sends the package back, indicating that delivery should be attempted again in the future. */
+- (void)retryDeliveryInTheFuture;
+
+@end
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORUploader.h b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORUploader.h
new file mode 100644
index 0000000..a34f8b2
--- /dev/null
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GDTCORUploader.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018 Google
+ *
+ * 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
+
+#import
+#import
+#import
+#import
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** This protocol defines the common interface for uploader implementations. */
+@protocol GDTCORUploader
+
+@required
+
+/** Returns YES if the uploader can make an upload attempt, NO otherwise.
+ *
+ * @param conditions The conditions that the upload attempt is likely to occur under.
+ * @return YES if the uploader can make an upload attempt, NO otherwise.
+ */
+- (BOOL)readyToUploadWithConditions:(GDTCORUploadConditions)conditions;
+
+/** Uploads events to the backend using this specific backend's chosen format.
+ *
+ * @param package The event package to upload. Make sure to call -completeDelivery.
+ */
+- (void)uploadPackage:(GDTCORUploadPackage *)package;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GoogleDataTransport.h b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GoogleDataTransport.h
new file mode 100644
index 0000000..e46a385
--- /dev/null
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Headers/GoogleDataTransport.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2018 Google
+ *
+ * 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 "GDTCORClock.h"
+#import "GDTCORConsoleLogger.h"
+#import "GDTCORDataFuture.h"
+#import "GDTCOREvent.h"
+#import "GDTCOREventDataObject.h"
+#import "GDTCOREventTransformer.h"
+#import "GDTCORLifecycle.h"
+#import "GDTCORPrioritizer.h"
+#import "GDTCORRegistrar.h"
+#import "GDTCORStoredEvent.h"
+#import "GDTCORTargets.h"
+#import "GDTCORTransport.h"
+#import "GDTCORUploadPackage.h"
+#import "GDTCORUploader.h"
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Modules/module.modulemap b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Modules/module.modulemap
new file mode 100644
index 0000000..fa35726
--- /dev/null
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransport.framework/Modules/module.modulemap
@@ -0,0 +1,5 @@
+framework module GoogleDataTransport {
+umbrella header "GoogleDataTransport.h"
+export *
+module * { export * }
+}
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransportCCTSupport.framework/GoogleDataTransportCCTSupport b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransportCCTSupport.framework/GoogleDataTransportCCTSupport
new file mode 100644
index 0000000..cbc30f8
Binary files /dev/null and b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransportCCTSupport.framework/GoogleDataTransportCCTSupport differ
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransportCCTSupport.framework/Headers/cct.nanopb.h b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransportCCTSupport.framework/Headers/cct.nanopb.h
new file mode 100644
index 0000000..a6d4cfb
--- /dev/null
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransportCCTSupport.framework/Headers/cct.nanopb.h
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2019 Google
+ *
+ * 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.
+ */
+
+/* Automatically generated nanopb header */
+/* Generated by nanopb-0.3.9.3 */
+
+#ifndef PB_GDT_CCT_CCT_NANOPB_H_INCLUDED
+#define PB_GDT_CCT_CCT_NANOPB_H_INCLUDED
+#include
+
+/* @@protoc_insertion_point(includes) */
+#if PB_PROTO_HEADER_VERSION != 30
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+
+/* Enum definitions */
+typedef enum _gdt_cct_NetworkConnectionInfo_NetworkType {
+ gdt_cct_NetworkConnectionInfo_NetworkType_NONE = -1,
+ gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE = 0,
+ gdt_cct_NetworkConnectionInfo_NetworkType_WIFI = 1,
+ gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_MMS = 2,
+ gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_SUPL = 3,
+ gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_DUN = 4,
+ gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_HIPRI = 5,
+ gdt_cct_NetworkConnectionInfo_NetworkType_WIMAX = 6,
+ gdt_cct_NetworkConnectionInfo_NetworkType_BLUETOOTH = 7,
+ gdt_cct_NetworkConnectionInfo_NetworkType_DUMMY = 8,
+ gdt_cct_NetworkConnectionInfo_NetworkType_ETHERNET = 9,
+ gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_FOTA = 10,
+ gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_IMS = 11,
+ gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_CBS = 12,
+ gdt_cct_NetworkConnectionInfo_NetworkType_WIFI_P2P = 13,
+ gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_IA = 14,
+ gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_EMERGENCY = 15,
+ gdt_cct_NetworkConnectionInfo_NetworkType_PROXY = 16,
+ gdt_cct_NetworkConnectionInfo_NetworkType_VPN = 17
+} gdt_cct_NetworkConnectionInfo_NetworkType;
+#define _gdt_cct_NetworkConnectionInfo_NetworkType_MIN gdt_cct_NetworkConnectionInfo_NetworkType_NONE
+#define _gdt_cct_NetworkConnectionInfo_NetworkType_MAX gdt_cct_NetworkConnectionInfo_NetworkType_VPN
+#define _gdt_cct_NetworkConnectionInfo_NetworkType_ARRAYSIZE ((gdt_cct_NetworkConnectionInfo_NetworkType)(gdt_cct_NetworkConnectionInfo_NetworkType_VPN+1))
+
+typedef enum _gdt_cct_NetworkConnectionInfo_MobileSubtype {
+ gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE = 0,
+ gdt_cct_NetworkConnectionInfo_MobileSubtype_GPRS = 1,
+ gdt_cct_NetworkConnectionInfo_MobileSubtype_EDGE = 2,
+ gdt_cct_NetworkConnectionInfo_MobileSubtype_UMTS = 3,
+ gdt_cct_NetworkConnectionInfo_MobileSubtype_CDMA = 4,
+ gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_0 = 5,
+ gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_A = 6,
+ gdt_cct_NetworkConnectionInfo_MobileSubtype_RTT = 7,
+ gdt_cct_NetworkConnectionInfo_MobileSubtype_HSDPA = 8,
+ gdt_cct_NetworkConnectionInfo_MobileSubtype_HSUPA = 9,
+ gdt_cct_NetworkConnectionInfo_MobileSubtype_HSPA = 10,
+ gdt_cct_NetworkConnectionInfo_MobileSubtype_IDEN = 11,
+ gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_B = 12,
+ gdt_cct_NetworkConnectionInfo_MobileSubtype_LTE = 13,
+ gdt_cct_NetworkConnectionInfo_MobileSubtype_EHRPD = 14,
+ gdt_cct_NetworkConnectionInfo_MobileSubtype_HSPAP = 15,
+ gdt_cct_NetworkConnectionInfo_MobileSubtype_GSM = 16,
+ gdt_cct_NetworkConnectionInfo_MobileSubtype_TD_SCDMA = 17,
+ gdt_cct_NetworkConnectionInfo_MobileSubtype_IWLAN = 18,
+ gdt_cct_NetworkConnectionInfo_MobileSubtype_LTE_CA = 19,
+ gdt_cct_NetworkConnectionInfo_MobileSubtype_COMBINED = 100
+} gdt_cct_NetworkConnectionInfo_MobileSubtype;
+#define _gdt_cct_NetworkConnectionInfo_MobileSubtype_MIN gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE
+#define _gdt_cct_NetworkConnectionInfo_MobileSubtype_MAX gdt_cct_NetworkConnectionInfo_MobileSubtype_COMBINED
+#define _gdt_cct_NetworkConnectionInfo_MobileSubtype_ARRAYSIZE ((gdt_cct_NetworkConnectionInfo_MobileSubtype)(gdt_cct_NetworkConnectionInfo_MobileSubtype_COMBINED+1))
+
+typedef enum _gdt_cct_ClientInfo_ClientType {
+ gdt_cct_ClientInfo_ClientType_CLIENT_UNKNOWN = 0,
+ gdt_cct_ClientInfo_ClientType_IOS_FIREBASE = 15
+} gdt_cct_ClientInfo_ClientType;
+#define _gdt_cct_ClientInfo_ClientType_MIN gdt_cct_ClientInfo_ClientType_CLIENT_UNKNOWN
+#define _gdt_cct_ClientInfo_ClientType_MAX gdt_cct_ClientInfo_ClientType_IOS_FIREBASE
+#define _gdt_cct_ClientInfo_ClientType_ARRAYSIZE ((gdt_cct_ClientInfo_ClientType)(gdt_cct_ClientInfo_ClientType_IOS_FIREBASE+1))
+
+typedef enum _gdt_cct_QosTierConfiguration_QosTier {
+ gdt_cct_QosTierConfiguration_QosTier_DEFAULT = 0,
+ gdt_cct_QosTierConfiguration_QosTier_UNMETERED_ONLY = 1,
+ gdt_cct_QosTierConfiguration_QosTier_UNMETERED_OR_DAILY = 2,
+ gdt_cct_QosTierConfiguration_QosTier_FAST_IF_RADIO_AWAKE = 3,
+ gdt_cct_QosTierConfiguration_QosTier_NEVER = 4
+} gdt_cct_QosTierConfiguration_QosTier;
+#define _gdt_cct_QosTierConfiguration_QosTier_MIN gdt_cct_QosTierConfiguration_QosTier_DEFAULT
+#define _gdt_cct_QosTierConfiguration_QosTier_MAX gdt_cct_QosTierConfiguration_QosTier_NEVER
+#define _gdt_cct_QosTierConfiguration_QosTier_ARRAYSIZE ((gdt_cct_QosTierConfiguration_QosTier)(gdt_cct_QosTierConfiguration_QosTier_NEVER+1))
+
+/* Struct definitions */
+typedef struct _gdt_cct_BatchedLogRequest {
+ pb_size_t log_request_count;
+ struct _gdt_cct_LogRequest *log_request;
+/* @@protoc_insertion_point(struct:gdt_cct_BatchedLogRequest) */
+} gdt_cct_BatchedLogRequest;
+
+typedef struct _gdt_cct_IosClientInfo {
+ pb_bytes_array_t *os_major_version;
+ pb_bytes_array_t *os_full_version;
+ pb_bytes_array_t *application_build;
+ pb_bytes_array_t *country;
+ pb_bytes_array_t *model;
+ pb_bytes_array_t *language_code;
+ pb_bytes_array_t *application_bundle_id;
+/* @@protoc_insertion_point(struct:gdt_cct_IosClientInfo) */
+} gdt_cct_IosClientInfo;
+
+typedef struct _gdt_cct_ClientInfo {
+ bool has_client_type;
+ gdt_cct_ClientInfo_ClientType client_type;
+ bool has_ios_client_info;
+ gdt_cct_IosClientInfo ios_client_info;
+/* @@protoc_insertion_point(struct:gdt_cct_ClientInfo) */
+} gdt_cct_ClientInfo;
+
+typedef struct _gdt_cct_NetworkConnectionInfo {
+ bool has_network_type;
+ gdt_cct_NetworkConnectionInfo_NetworkType network_type;
+ bool has_mobile_subtype;
+ gdt_cct_NetworkConnectionInfo_MobileSubtype mobile_subtype;
+/* @@protoc_insertion_point(struct:gdt_cct_NetworkConnectionInfo) */
+} gdt_cct_NetworkConnectionInfo;
+
+typedef struct _gdt_cct_QosTierConfiguration {
+ bool has_qos_tier;
+ gdt_cct_QosTierConfiguration_QosTier qos_tier;
+ bool has_log_source;
+ int32_t log_source;
+/* @@protoc_insertion_point(struct:gdt_cct_QosTierConfiguration) */
+} gdt_cct_QosTierConfiguration;
+
+typedef struct _gdt_cct_QosTiersOverride {
+ pb_size_t qos_tier_configuration_count;
+ struct _gdt_cct_QosTierConfiguration *qos_tier_configuration;
+ bool has_qos_tier_fingerprint;
+ int64_t qos_tier_fingerprint;
+/* @@protoc_insertion_point(struct:gdt_cct_QosTiersOverride) */
+} gdt_cct_QosTiersOverride;
+
+typedef struct _gdt_cct_LogEvent {
+ bool has_event_time_ms;
+ int64_t event_time_ms;
+ pb_bytes_array_t *source_extension;
+ bool has_event_code;
+ int32_t event_code;
+ bool has_timezone_offset_seconds;
+ int64_t timezone_offset_seconds;
+ bool has_event_uptime_ms;
+ int64_t event_uptime_ms;
+ bool has_network_connection_info;
+ gdt_cct_NetworkConnectionInfo network_connection_info;
+/* @@protoc_insertion_point(struct:gdt_cct_LogEvent) */
+} gdt_cct_LogEvent;
+
+typedef struct _gdt_cct_LogRequest {
+ bool has_client_info;
+ gdt_cct_ClientInfo client_info;
+ bool has_log_source;
+ int32_t log_source;
+ pb_size_t log_event_count;
+ struct _gdt_cct_LogEvent *log_event;
+ bool has_request_time_ms;
+ int64_t request_time_ms;
+ bool has_request_uptime_ms;
+ int64_t request_uptime_ms;
+ bool has_qos_tier;
+ gdt_cct_QosTierConfiguration_QosTier qos_tier;
+/* @@protoc_insertion_point(struct:gdt_cct_LogRequest) */
+} gdt_cct_LogRequest;
+
+typedef struct _gdt_cct_LogResponse {
+ bool has_next_request_wait_millis;
+ int64_t next_request_wait_millis;
+ bool has_qos_tier;
+ gdt_cct_QosTiersOverride qos_tier;
+/* @@protoc_insertion_point(struct:gdt_cct_LogResponse) */
+} gdt_cct_LogResponse;
+
+/* Default values for struct fields */
+extern const gdt_cct_NetworkConnectionInfo_NetworkType gdt_cct_NetworkConnectionInfo_network_type_default;
+extern const gdt_cct_NetworkConnectionInfo_MobileSubtype gdt_cct_NetworkConnectionInfo_mobile_subtype_default;
+extern const gdt_cct_QosTierConfiguration_QosTier gdt_cct_LogRequest_qos_tier_default;
+extern const int32_t gdt_cct_QosTierConfiguration_log_source_default;
+
+/* Initializer values for message structs */
+#define gdt_cct_LogEvent_init_default {false, 0, NULL, false, 0, false, 0, false, 0, false, gdt_cct_NetworkConnectionInfo_init_default}
+#define gdt_cct_NetworkConnectionInfo_init_default {false, gdt_cct_NetworkConnectionInfo_NetworkType_NONE, false, gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE}
+#define gdt_cct_IosClientInfo_init_default {NULL, NULL, NULL, NULL, NULL, NULL, NULL}
+#define gdt_cct_ClientInfo_init_default {false, _gdt_cct_ClientInfo_ClientType_MIN, false, gdt_cct_IosClientInfo_init_default}
+#define gdt_cct_BatchedLogRequest_init_default {0, NULL}
+#define gdt_cct_LogRequest_init_default {false, gdt_cct_ClientInfo_init_default, false, 0, 0, NULL, false, 0, false, 0, false, gdt_cct_QosTierConfiguration_QosTier_DEFAULT}
+#define gdt_cct_QosTierConfiguration_init_default {false, _gdt_cct_QosTierConfiguration_QosTier_MIN, false, 0}
+#define gdt_cct_QosTiersOverride_init_default {0, NULL, false, 0}
+#define gdt_cct_LogResponse_init_default {false, 0, false, gdt_cct_QosTiersOverride_init_default}
+#define gdt_cct_LogEvent_init_zero {false, 0, NULL, false, 0, false, 0, false, 0, false, gdt_cct_NetworkConnectionInfo_init_zero}
+#define gdt_cct_NetworkConnectionInfo_init_zero {false, _gdt_cct_NetworkConnectionInfo_NetworkType_MIN, false, _gdt_cct_NetworkConnectionInfo_MobileSubtype_MIN}
+#define gdt_cct_IosClientInfo_init_zero {NULL, NULL, NULL, NULL, NULL, NULL, NULL}
+#define gdt_cct_ClientInfo_init_zero {false, _gdt_cct_ClientInfo_ClientType_MIN, false, gdt_cct_IosClientInfo_init_zero}
+#define gdt_cct_BatchedLogRequest_init_zero {0, NULL}
+#define gdt_cct_LogRequest_init_zero {false, gdt_cct_ClientInfo_init_zero, false, 0, 0, NULL, false, 0, false, 0, false, _gdt_cct_QosTierConfiguration_QosTier_MIN}
+#define gdt_cct_QosTierConfiguration_init_zero {false, _gdt_cct_QosTierConfiguration_QosTier_MIN, false, 0}
+#define gdt_cct_QosTiersOverride_init_zero {0, NULL, false, 0}
+#define gdt_cct_LogResponse_init_zero {false, 0, false, gdt_cct_QosTiersOverride_init_zero}
+
+/* Field tags (for use in manual encoding/decoding) */
+#define gdt_cct_BatchedLogRequest_log_request_tag 1
+#define gdt_cct_IosClientInfo_os_major_version_tag 3
+#define gdt_cct_IosClientInfo_os_full_version_tag 4
+#define gdt_cct_IosClientInfo_application_build_tag 5
+#define gdt_cct_IosClientInfo_country_tag 6
+#define gdt_cct_IosClientInfo_model_tag 7
+#define gdt_cct_IosClientInfo_language_code_tag 8
+#define gdt_cct_IosClientInfo_application_bundle_id_tag 11
+#define gdt_cct_ClientInfo_client_type_tag 1
+#define gdt_cct_ClientInfo_ios_client_info_tag 4
+#define gdt_cct_NetworkConnectionInfo_network_type_tag 1
+#define gdt_cct_NetworkConnectionInfo_mobile_subtype_tag 2
+#define gdt_cct_QosTierConfiguration_qos_tier_tag 2
+#define gdt_cct_QosTierConfiguration_log_source_tag 3
+#define gdt_cct_QosTiersOverride_qos_tier_configuration_tag 1
+#define gdt_cct_QosTiersOverride_qos_tier_fingerprint_tag 2
+#define gdt_cct_LogEvent_event_time_ms_tag 1
+#define gdt_cct_LogEvent_event_code_tag 11
+#define gdt_cct_LogEvent_event_uptime_ms_tag 17
+#define gdt_cct_LogEvent_source_extension_tag 6
+#define gdt_cct_LogEvent_timezone_offset_seconds_tag 15
+#define gdt_cct_LogEvent_network_connection_info_tag 23
+#define gdt_cct_LogRequest_request_time_ms_tag 4
+#define gdt_cct_LogRequest_request_uptime_ms_tag 8
+#define gdt_cct_LogRequest_client_info_tag 1
+#define gdt_cct_LogRequest_log_source_tag 2
+#define gdt_cct_LogRequest_log_event_tag 3
+#define gdt_cct_LogRequest_qos_tier_tag 9
+#define gdt_cct_LogResponse_next_request_wait_millis_tag 1
+#define gdt_cct_LogResponse_qos_tier_tag 3
+
+/* Struct field encoding specification for nanopb */
+extern const pb_field_t gdt_cct_LogEvent_fields[7];
+extern const pb_field_t gdt_cct_NetworkConnectionInfo_fields[3];
+extern const pb_field_t gdt_cct_IosClientInfo_fields[8];
+extern const pb_field_t gdt_cct_ClientInfo_fields[3];
+extern const pb_field_t gdt_cct_BatchedLogRequest_fields[2];
+extern const pb_field_t gdt_cct_LogRequest_fields[7];
+extern const pb_field_t gdt_cct_QosTierConfiguration_fields[3];
+extern const pb_field_t gdt_cct_QosTiersOverride_fields[3];
+extern const pb_field_t gdt_cct_LogResponse_fields[3];
+
+/* Maximum encoded size of messages (where known) */
+/* gdt_cct_LogEvent_size depends on runtime parameters */
+#define gdt_cct_NetworkConnectionInfo_size 13
+/* gdt_cct_IosClientInfo_size depends on runtime parameters */
+/* gdt_cct_ClientInfo_size depends on runtime parameters */
+/* gdt_cct_BatchedLogRequest_size depends on runtime parameters */
+/* gdt_cct_LogRequest_size depends on runtime parameters */
+#define gdt_cct_QosTierConfiguration_size 13
+/* gdt_cct_QosTiersOverride_size depends on runtime parameters */
+/* gdt_cct_LogResponse_size depends on runtime parameters */
+
+/* Message IDs (where set with "msgid" option) */
+#ifdef PB_MSGID
+
+#define CCT_MESSAGES \
+
+
+#endif
+
+/* @@protoc_insertion_point(eof) */
+
+#endif
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransportCCTSupport.framework/Modules/module.modulemap b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransportCCTSupport.framework/Modules/module.modulemap
new file mode 100644
index 0000000..13c7fcf
--- /dev/null
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleDataTransportCCTSupport.framework/Modules/module.modulemap
@@ -0,0 +1,6 @@
+framework module GoogleDataTransportCCTSupport {
+umbrella header "GoogleDataTransportCCTSupport.h"
+export *
+module * { export * }
+ link "z"
+}
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleToolboxForMac.framework/GoogleToolboxForMac b/WikiRaces/Shared/Frameworks/Analytics/GoogleToolboxForMac.framework/GoogleToolboxForMac
index 705418c..a94e900 100644
Binary files a/WikiRaces/Shared/Frameworks/Analytics/GoogleToolboxForMac.framework/GoogleToolboxForMac and b/WikiRaces/Shared/Frameworks/Analytics/GoogleToolboxForMac.framework/GoogleToolboxForMac differ
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleToolboxForMac.framework/Headers/GTMDebugSelectorValidation.h b/WikiRaces/Shared/Frameworks/Analytics/GoogleToolboxForMac.framework/Headers/GTMDebugSelectorValidation.h
index c90caeb..0c4c4da 100644
--- a/WikiRaces/Shared/Frameworks/Analytics/GoogleToolboxForMac.framework/Headers/GTMDebugSelectorValidation.h
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleToolboxForMac.framework/Headers/GTMDebugSelectorValidation.h
@@ -31,6 +31,7 @@
#if DEBUG
#import
+#import
#import "GTMDefines.h"
static void GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(id obj, SEL sel, const char *retType, ...) {
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleUtilities.framework/GoogleUtilities b/WikiRaces/Shared/Frameworks/Analytics/GoogleUtilities.framework/GoogleUtilities
index 38ce2ca..67fbf48 100644
Binary files a/WikiRaces/Shared/Frameworks/Analytics/GoogleUtilities.framework/GoogleUtilities and b/WikiRaces/Shared/Frameworks/Analytics/GoogleUtilities.framework/GoogleUtilities differ
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleUtilities.framework/Headers/GULLoggerCodes.h b/WikiRaces/Shared/Frameworks/Analytics/GoogleUtilities.framework/Headers/GULLoggerCodes.h
index fd22ba6..2320ed3 100644
--- a/WikiRaces/Shared/Frameworks/Analytics/GoogleUtilities.framework/Headers/GULLoggerCodes.h
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleUtilities.framework/Headers/GULLoggerCodes.h
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#import
+
typedef NS_ENUM(NSInteger, GULSwizzlerMessageCode) {
// App Delegate Swizzling.
kGULSwizzlerMessageCodeAppDelegateSwizzling000 = 1000, // I-SWZ001000
diff --git a/WikiRaces/Shared/Frameworks/Analytics/GoogleUtilities.framework/Headers/GULLoggerLevel.h b/WikiRaces/Shared/Frameworks/Analytics/GoogleUtilities.framework/Headers/GULLoggerLevel.h
index 81ff212..f0ee435 100644
--- a/WikiRaces/Shared/Frameworks/Analytics/GoogleUtilities.framework/Headers/GULLoggerLevel.h
+++ b/WikiRaces/Shared/Frameworks/Analytics/GoogleUtilities.framework/Headers/GULLoggerLevel.h
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#import
+
/**
* The log levels used by internal logging.
*/
diff --git a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Any.pbobjc.h b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Any.pbobjc.h
index 2091d72..f22c8c5 100644
--- a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Any.pbobjc.h
+++ b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Any.pbobjc.h
@@ -8,9 +8,9 @@
#endif
#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
- #import
- #import
- #import
+ #import
+ #import
+ #import
#else
#import "GPBDescriptor.h"
#import "GPBMessage.h"
diff --git a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Api.pbobjc.h b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Api.pbobjc.h
index c93f3f1..99acd04 100644
--- a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Api.pbobjc.h
+++ b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Api.pbobjc.h
@@ -8,9 +8,9 @@
#endif
#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
- #import
- #import
- #import
+ #import
+ #import
+ #import
#else
#import "GPBDescriptor.h"
#import "GPBMessage.h"
diff --git a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Duration.pbobjc.h b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Duration.pbobjc.h
index 3e36759..111a910 100644
--- a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Duration.pbobjc.h
+++ b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Duration.pbobjc.h
@@ -8,9 +8,9 @@
#endif
#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
- #import
- #import
- #import
+ #import
+ #import
+ #import
#else
#import "GPBDescriptor.h"
#import "GPBMessage.h"
@@ -77,7 +77,7 @@ typedef GPB_ENUM(GPBDuration_FieldNumber) {
* if (duration.seconds < 0 && duration.nanos > 0) {
* duration.seconds += 1;
* duration.nanos -= 1000000000;
- * } else if (durations.seconds > 0 && duration.nanos < 0) {
+ * } else if (duration.seconds > 0 && duration.nanos < 0) {
* duration.seconds -= 1;
* duration.nanos += 1000000000;
* }
diff --git a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Empty.pbobjc.h b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Empty.pbobjc.h
index fdc247a..5b1e7b4 100644
--- a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Empty.pbobjc.h
+++ b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Empty.pbobjc.h
@@ -8,9 +8,9 @@
#endif
#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
- #import
- #import
- #import
+ #import
+ #import
+ #import
#else
#import "GPBDescriptor.h"
#import "GPBMessage.h"
diff --git a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/FieldMask.pbobjc.h b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/FieldMask.pbobjc.h
index 72cac9a..61fdd25 100644
--- a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/FieldMask.pbobjc.h
+++ b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/FieldMask.pbobjc.h
@@ -8,9 +8,9 @@
#endif
#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
- #import
- #import
- #import
+ #import
+ #import
+ #import
#else
#import "GPBDescriptor.h"
#import "GPBMessage.h"
diff --git a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBDescriptor.h b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBDescriptor.h
index 292bce1..331d444 100644
--- a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBDescriptor.h
+++ b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBDescriptor.h
@@ -75,7 +75,7 @@ typedef NS_ENUM(uint8_t, GPBFieldType) {
/** Number of extension ranges declared for the message. */
@property(nonatomic, readonly) uint32_t extensionRangesCount;
/** Descriptor for the file where the message was defined. */
-@property(nonatomic, readonly, assign) GPBFileDescriptor *file;
+@property(nonatomic, readonly) GPBFileDescriptor *file;
/** Whether the message is in wire format or not. */
@property(nonatomic, readonly, getter=isWireFormat) BOOL wireFormat;
@@ -188,10 +188,10 @@ typedef NS_ENUM(uint8_t, GPBFieldType) {
@property(nonatomic, readonly, getter=isPackable) BOOL packable;
/** The containing oneof if this field is part of one, nil otherwise. */
-@property(nonatomic, readonly, assign, nullable) GPBOneofDescriptor *containingOneof;
+@property(nonatomic, readonly, nullable) GPBOneofDescriptor *containingOneof;
/** Class of the message if the field is of message type. */
-@property(nonatomic, readonly, assign, nullable) Class msgClass;
+@property(nonatomic, readonly, nullable) Class msgClass;
/** Descriptor for the enum if this field is an enum. */
@property(nonatomic, readonly, strong, nullable) GPBEnumDescriptor *enumDescriptor;
@@ -305,7 +305,7 @@ typedef NS_ENUM(uint8_t, GPBFieldType) {
/** Whether the extension is packable. */
@property(nonatomic, readonly, getter=isPackable) BOOL packable;
/** The class of the message if the extension is of message type. */
-@property(nonatomic, readonly, assign) Class msgClass;
+@property(nonatomic, readonly) Class msgClass;
/** The singleton name for the extension. */
@property(nonatomic, readonly) NSString *singletonName;
/** The enum descriptor if the extension is of enum type. */
diff --git a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBMessage.h b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBMessage.h
index 276740d..01253a4 100644
--- a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBMessage.h
+++ b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBMessage.h
@@ -308,7 +308,7 @@ CF_EXTERN_C_END
- (void)writeToOutputStream:(NSOutputStream *)output;
/**
- * Writes out a varint for the message size followed by the the message to
+ * Writes out a varint for the message size followed by the message to
* the given output stream.
*
* @param output The coded output stream into which to write the message.
@@ -318,7 +318,7 @@ CF_EXTERN_C_END
- (void)writeDelimitedToCodedOutputStream:(GPBCodedOutputStream *)output;
/**
- * Writes out a varint for the message size followed by the the message to
+ * Writes out a varint for the message size followed by the message to
* the given output stream.
*
* @param output The output stream into which to write the message.
diff --git a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBProtocolBuffers.h b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBProtocolBuffers.h
index 68d8854..32f9f5d 100644
--- a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBProtocolBuffers.h
+++ b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBProtocolBuffers.h
@@ -52,16 +52,16 @@
// Well-known proto types
#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
- #import
- #import
- #import
- #import
- #import
- #import
- #import
- #import
- #import
- #import
+ #import
+ #import
+ #import
+ #import
+ #import
+ #import
+ #import
+ #import
+ #import
+ #import
#else
#import "google/protobuf/Any.pbobjc.h"
#import "google/protobuf/Api.pbobjc.h"
diff --git a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBRuntimeTypes.h b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBRuntimeTypes.h
index 4d55206..8148054 100644
--- a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBRuntimeTypes.h
+++ b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBRuntimeTypes.h
@@ -74,7 +74,7 @@ typedef union {
/**
* Enum listing the possible data types that a field can contain.
- *
+ *
* @note Do not change the order of this enum (or add things to it) without
* thinking about it very carefully. There are several things that depend
* on the order.
diff --git a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBUtilities_PackagePrivate.h b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBUtilities_PackagePrivate.h
index ed424ce..336a745 100644
--- a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBUtilities_PackagePrivate.h
+++ b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBUtilities_PackagePrivate.h
@@ -71,27 +71,31 @@ GPB_INLINE void GPBDebugCheckRuntimeVersion() {
// Conversion functions for de/serializing floating point types.
GPB_INLINE int64_t GPBConvertDoubleToInt64(double v) {
- union { double f; int64_t i; } u;
- u.f = v;
- return u.i;
+ GPBInternalCompileAssert(sizeof(double) == sizeof(int64_t), double_not_64_bits);
+ int64_t result;
+ memcpy(&result, &v, sizeof(result));
+ return result;
}
GPB_INLINE int32_t GPBConvertFloatToInt32(float v) {
- union { float f; int32_t i; } u;
- u.f = v;
- return u.i;
+ GPBInternalCompileAssert(sizeof(float) == sizeof(int32_t), float_not_32_bits);
+ int32_t result;
+ memcpy(&result, &v, sizeof(result));
+ return result;
}
GPB_INLINE double GPBConvertInt64ToDouble(int64_t v) {
- union { double f; int64_t i; } u;
- u.i = v;
- return u.f;
+ GPBInternalCompileAssert(sizeof(double) == sizeof(int64_t), double_not_64_bits);
+ double result;
+ memcpy(&result, &v, sizeof(result));
+ return result;
}
GPB_INLINE float GPBConvertInt32ToFloat(int32_t v) {
- union { float f; int32_t i; } u;
- u.i = v;
- return u.f;
+ GPBInternalCompileAssert(sizeof(float) == sizeof(int32_t), float_not_32_bits);
+ float result;
+ memcpy(&result, &v, sizeof(result));
+ return result;
}
GPB_INLINE int32_t GPBLogicalRightShift32(int32_t value, int32_t spaces) {
diff --git a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBWellKnownTypes.h b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBWellKnownTypes.h
index 04df417..bb6c780 100644
--- a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBWellKnownTypes.h
+++ b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/GPBWellKnownTypes.h
@@ -37,9 +37,9 @@
#endif
#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
- #import
- #import
- #import
+ #import
+ #import
+ #import
#else
#import "google/protobuf/Any.pbobjc.h"
#import "google/protobuf/Duration.pbobjc.h"
diff --git a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/SourceContext.pbobjc.h b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/SourceContext.pbobjc.h
index e492395..b2cdbba 100644
--- a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/SourceContext.pbobjc.h
+++ b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/SourceContext.pbobjc.h
@@ -8,9 +8,9 @@
#endif
#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
- #import
- #import
- #import
+ #import
+ #import
+ #import
#else
#import "GPBDescriptor.h"
#import "GPBMessage.h"
diff --git a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Struct.pbobjc.h b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Struct.pbobjc.h
index fb20425..8a06de4 100644
--- a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Struct.pbobjc.h
+++ b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Struct.pbobjc.h
@@ -8,9 +8,9 @@
#endif
#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
- #import
- #import
- #import
+ #import
+ #import
+ #import
#else
#import "GPBDescriptor.h"
#import "GPBMessage.h"
diff --git a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Timestamp.pbobjc.h b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Timestamp.pbobjc.h
index f6ea25c..d351f27 100644
--- a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Timestamp.pbobjc.h
+++ b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Timestamp.pbobjc.h
@@ -8,9 +8,9 @@
#endif
#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
- #import
- #import
- #import
+ #import
+ #import
+ #import
#else
#import "GPBDescriptor.h"
#import "GPBMessage.h"
@@ -129,11 +129,13 @@ typedef GPB_ENUM(GPBTimestamp_FieldNumber) {
* 01:30 UTC on January 15, 2017.
*
* In JavaScript, one can convert a Date object to this format using the
- * standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
+ * standard
+ * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
* method. In Python, a standard `datetime.datetime` object can be converted
- * to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
- * with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
- * can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
+ * to this format using
+ * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with
+ * the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use
+ * the Joda Time's [`ISODateTimeFormat.dateTime()`](
* http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D
* ) to obtain a formatter capable of generating timestamps in this format.
**/
diff --git a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Type.pbobjc.h b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Type.pbobjc.h
index e14d15d..5a54863 100644
--- a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Type.pbobjc.h
+++ b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Type.pbobjc.h
@@ -8,9 +8,9 @@
#endif
#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
- #import
- #import
- #import
+ #import
+ #import
+ #import
#else
#import "GPBDescriptor.h"
#import "GPBMessage.h"
diff --git a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Wrappers.pbobjc.h b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Wrappers.pbobjc.h
index 0411e1e..a9d3646 100644
--- a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Wrappers.pbobjc.h
+++ b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Headers/Wrappers.pbobjc.h
@@ -8,9 +8,9 @@
#endif
#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
- #import
- #import
- #import
+ #import
+ #import
+ #import
#else
#import "GPBDescriptor.h"
#import "GPBMessage.h"
diff --git a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Protobuf b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Protobuf
index ba7b25a..fe22576 100644
Binary files a/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Protobuf and b/WikiRaces/Shared/Frameworks/Analytics/Protobuf.framework/Protobuf differ
diff --git a/WikiRaces/Shared/Frameworks/Analytics/nanopb.framework/nanopb b/WikiRaces/Shared/Frameworks/Analytics/nanopb.framework/nanopb
index ef80760..77e1b58 100644
Binary files a/WikiRaces/Shared/Frameworks/Analytics/nanopb.framework/nanopb and b/WikiRaces/Shared/Frameworks/Analytics/nanopb.framework/nanopb differ
diff --git a/WikiRaces/Shared/Logging/PlayerAnonymousMetrics.swift b/WikiRaces/Shared/Logging/PlayerAnonymousMetrics.swift
index 3921b76..59b980d 100644
--- a/WikiRaces/Shared/Logging/PlayerAnonymousMetrics.swift
+++ b/WikiRaces/Shared/Logging/PlayerAnonymousMetrics.swift
@@ -9,7 +9,7 @@
import UIKit
import WKRKit
-#if !MULTIWINDOWDEBUG
+#if !targetEnvironment(macCatalyst) && !MULTIWINDOWDEBUG
import Crashlytics
import FirebaseCore
#endif
@@ -31,7 +31,7 @@ internal struct PlayerAnonymousMetrics {
case leaderboard, versionInfo
case pressedJoin, pressedHost, pressedGlobalJoin, pressedLocalOptions
case namePromptResult, nameType
- case cloudStatus, interfaceMode
+ case cloudStatus, interfaceMode, autoInviteToggled, autoInviteState
// Game All Players
case pageView, pageBlocked, pageError
@@ -78,7 +78,7 @@ internal struct PlayerAnonymousMetrics {
// MARK: - Logging Events
public static func log(event: CrashLogEvent) {
- #if MULTIWINDOWDEBUG
+ #if MULTIWINDOWDEBUG || targetEnvironment(macCatalyst)
switch event {
case .userAction(let action):
print("UserAction: ", action)
@@ -102,7 +102,7 @@ internal struct PlayerAnonymousMetrics {
// MARK: - Analytic Events
public static func log(event: Event, attributes: [String: Any]? = nil) {
- #if !MULTIWINDOWDEBUG && !DEBUG
+ #if !targetEnvironment(macCatalyst) && !MULTIWINDOWDEBUG && !DEBUG
Answers.logCustomEvent(withName: event.rawValue, customAttributes: attributes)
if !(attributes?.values.compactMap { $0 }.isEmpty ?? true) {
Analytics.logEvent(event.rawValue, parameters: attributes)
diff --git a/WikiRaces/Shared/Logging/PlayerDatabaseMetrics.swift b/WikiRaces/Shared/Logging/PlayerDatabaseMetrics.swift
index 15abfb3..70370fd 100644
--- a/WikiRaces/Shared/Logging/PlayerDatabaseMetrics.swift
+++ b/WikiRaces/Shared/Logging/PlayerDatabaseMetrics.swift
@@ -12,7 +12,7 @@ import WKRKit
class PlayerDatabaseMetrics: NSObject {
- // MARK: - Types
+ // MARK: - Types -
private struct ProcessedResults {
let csvURL: URL
@@ -23,7 +23,7 @@ class PlayerDatabaseMetrics: NSObject {
static let banHammerNotification = Notification.Name("banHammerNotification")
- // MARK: - Properties
+ // MARK: - Properties -
static var shared = PlayerDatabaseMetrics()
@@ -39,7 +39,7 @@ class PlayerDatabaseMetrics: NSObject {
private var queuedKeyValues = [String: CKRecordValueProtocol]()
- // MARK: - Connecting
+ // MARK: - Connecting -
func connect() {
#if MULTIWINDOWDEBUG
@@ -49,47 +49,61 @@ class PlayerDatabaseMetrics: NSObject {
guard !isConnecting else { return }
isConnecting = true
- container.fetchUserRecordID(completionHandler: { (userRecordID, _) in
- guard let userRecordID = userRecordID else {
- self.isConnecting = false
+ // seperated out due to type checking time
+
+ // step 2, get the user main record
+ func fetched(userRecord: CKRecord?) {
+ self.userRecord = userRecord
+ guard let userRecord = userRecord else {
+ isConnecting = false
+ return
+ }
+
+ // negative races indicates ban
+ if let raceCount = userRecord["Races"] as? NSNumber, raceCount.intValue == -1 {
+ DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
+ let name = PlayerDatabaseMetrics.banHammerNotification
+ NotificationCenter.default.post(name: name, object: nil)
+ })
return
}
- self.publicDB.fetch(withRecordID: userRecordID, completionHandler: { (userRecord, _) in
- self.userRecord = userRecord
- guard let userRecord = userRecord else {
+
+ // Get user stats record, or create new one.
+ guard let statsRecordName = userRecord.object(forKey: "UserStatsNamev3") as? NSString,
+ statsRecordName.length > 5 else {
+ self.createUserStatsRecord()
self.isConnecting = false
return
- }
+ }
+ let userStatsRecordID = CKRecord.ID(recordName: statsRecordName as String)
+ self.publicDB.fetch(withRecordID: userStatsRecordID, completionHandler: { userStatsRecord, error in
+ fetched(userStatsRecord: userStatsRecord, error: error)
+ })
+ }
- if let raceCount = userRecord["Races"] as? NSNumber, raceCount.intValue == -1 {
- DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
- let name = PlayerDatabaseMetrics.banHammerNotification
- NotificationCenter.default.post(name: name, object: nil)
- })
- return
- }
+ // step 3, get the current user stats record
+ func fetched(userStatsRecord: CKRecord?, error: Error?) {
+ if let error = error as? CKError, error.code == CKError.unknownItem {
+ createUserStatsRecord()
+ isConnecting = false
+ return
+ }
+ guard let userStatsRecord = userStatsRecord else { return }
+ self.userStatsRecord = userStatsRecord
+ isConnecting = false
+ DispatchQueue.main.async {
+ self.saveKeyValues()
+ }
+ }
- // Get user stats record, or create new one.
- guard let statsRecordName = userRecord.object(forKey: "UserStatsNamev3") as? NSString,
- statsRecordName.length > 5 else {
- self.createUserStatsRecord()
- self.isConnecting = false
- return
- }
- let userStatsRecordID = CKRecord.ID(recordName: statsRecordName as String)
- self.publicDB.fetch(withRecordID: userStatsRecordID, completionHandler: { (userStatsRecord, error) in
- if let error = error as? CKError, error.code == CKError.unknownItem {
- self.createUserStatsRecord()
- self.isConnecting = false
- return
- }
- guard let userStatsRecord = userStatsRecord else { return }
- self.userStatsRecord = userStatsRecord
- self.isConnecting = false
- DispatchQueue.main.async {
- self.saveKeyValues()
- }
- })
+ // step 1
+ container.fetchUserRecordID(completionHandler: { userRecordID, _ in
+ guard let userRecordID = userRecordID else {
+ self.isConnecting = false
+ return
+ }
+ self.publicDB.fetch(withRecordID: userRecordID, completionHandler: { userRecord, _ in
+ fetched(userRecord: userRecord)
})
})
}
@@ -118,7 +132,7 @@ class PlayerDatabaseMetrics: NSObject {
})
}
- // MARK: - Events
+ // MARK: - Events -
func log(value: CKRecordValueProtocol, for key: String) {
DispatchQueue.main.async {
diff --git a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/ConnectViewController.swift b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/ConnectViewController.swift
index 1c5e91f..f3f8411 100644
--- a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/ConnectViewController.swift
+++ b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/ConnectViewController.swift
@@ -8,16 +8,17 @@
import UIKit
import WKRKit
+import WKRUIKit
class ConnectViewController: UIViewController {
- // MARK: - Types
+ // MARK: - Types -
struct StartMessage: Codable {
let hostName: String
}
- // MARK: - Interface Elements
+ // MARK: - Interface Elements -
/// General status label
let descriptionLabel = UILabel()
@@ -30,10 +31,10 @@ class ConnectViewController: UIViewController {
var isShowingMatch = false
var onQuit: (() -> Void)?
- // MARK: - Connection
+ // MARK: - Connection -
func runConnectionTest(completion: @escaping (Bool) -> Void) {
- #if !MULTIWINDOWDEBUG
+ #if !MULTIWINDOWDEBUG && !targetEnvironment(macCatalyst)
let trace = Performance.startTrace(name: "Connection Test Trace")
#endif
@@ -41,7 +42,7 @@ class ConnectViewController: UIViewController {
WKRConnectionTester.start { success in
DispatchQueue.main.async {
if success {
- #if !MULTIWINDOWDEBUG
+ #if !MULTIWINDOWDEBUG && !targetEnvironment(macCatalyst)
trace?.stop()
#endif
}
@@ -55,7 +56,7 @@ class ConnectViewController: UIViewController {
}
}
- // MARK: - View Life Cycle
+ // MARK: - View Life Cycle -
override func viewDidLoad() {
super.viewDidLoad()
@@ -69,20 +70,28 @@ class ConnectViewController: UIViewController {
cancelButton.alpha = 0.0
}
- // MARK: - Core Interface
+ override func viewWillLayoutSubviews() {
+ super.viewWillLayoutSubviews()
+ let textColor: UIColor = .wkrTextColor(for: traitCollection)
+ cancelButton.setTitleColor(textColor, for: .normal)
+ descriptionLabel.textColor = textColor
+ activityIndicatorView.color = .wkrActivityIndicatorColor(for: traitCollection)
+ view.backgroundColor = .wkrBackgroundColor(for: traitCollection)
+ }
+
+ // MARK: - Core Interface -
func setupCoreInterface() {
+ cancelButton.setAttributedTitle(NSAttributedString(string: "CANCEL",
+ spacing: 1.5), for: .normal)
cancelButton.translatesAutoresizingMaskIntoConstraints = false
cancelButton.titleLabel?.font = UIFont.systemFont(ofSize: 17, weight: .medium)
- cancelButton.setTitleColor(.wkrTextColor, for: .normal)
cancelButton.alpha = 0.0
- cancelButton.setAttributedTitle(NSAttributedString(string: "CANCEL", spacing: 1.5), for: .normal)
cancelButton.addTarget(self, action: #selector(pressedCancelButton), for: .touchUpInside)
view.addSubview(cancelButton)
descriptionLabel.translatesAutoresizingMaskIntoConstraints = false
descriptionLabel.alpha = 0.0
- descriptionLabel.textColor = .wkrTextColor
descriptionLabel.textAlignment = .center
descriptionLabel.font = UIFont.systemFont(ofSize: 17, weight: .medium)
view.addSubview(descriptionLabel)
@@ -90,7 +99,6 @@ class ConnectViewController: UIViewController {
activityIndicatorView.translatesAutoresizingMaskIntoConstraints = false
activityIndicatorView.alpha = 0.0
- activityIndicatorView.color = UIColor.wkrActivityIndicatorColor
activityIndicatorView.startAnimating()
view.addSubview(activityIndicatorView)
@@ -103,8 +111,6 @@ class ConnectViewController: UIViewController {
cancelButton.centerXAnchor.constraint(equalTo: view.centerXAnchor)
]
NSLayoutConstraint.activate(constraints)
-
- view.backgroundColor = UIColor.wkrBackgroundColor
}
func toggleCoreInterface(isHidden: Bool,
@@ -120,7 +126,7 @@ class ConnectViewController: UIViewController {
})
}
- // MARK: - Interface Updates
+ // MARK: - Interface Updates -
func updateDescriptionLabel(to text: String) {
descriptionLabel.attributedText = NSAttributedString(string: text.uppercased(),
@@ -188,11 +194,14 @@ class ConnectViewController: UIViewController {
completion: {
let controller = GameViewController()
controller.networkConfig = networkConfig
- let nav = UINavigationController(rootViewController: controller)
+ let nav = WKRUINavigationController(rootViewController: controller)
+ nav.modalPresentationStyle = .fullScreen
nav.modalTransitionStyle = .crossDissolve
+ if #available(iOS 13.0, *) {
+ nav.isModalInPresentation = true
+ }
self.present(nav, animated: true, completion: nil)
})
}
}
-
}
diff --git a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/GameKit/GameKitConnectViewController+Match.swift b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/GameKit/GameKitConnectViewController+Match.swift
index e80ca7a..a075303 100644
--- a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/GameKit/GameKitConnectViewController+Match.swift
+++ b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/GameKit/GameKitConnectViewController+Match.swift
@@ -11,7 +11,7 @@ import WKRKit
extension GameKitConnectViewController: GKMatchDelegate, GKMatchmakerViewControllerDelegate {
- // MARK: - Helpers
+ // MARK: - Helpers -
func findMatch() {
let request = GKMatchRequest()
@@ -28,7 +28,7 @@ extension GameKitConnectViewController: GKMatchDelegate, GKMatchmakerViewControl
} else if let controller = GKMatchmakerViewController(matchRequest: request) {
controller.matchmakerDelegate = self
present(controller, animated: true, completion: nil)
- #if !MULTIWINDOWDEBUG
+ #if !MULTIWINDOWDEBUG && !targetEnvironment(macCatalyst)
findTrace = Performance.startTrace(name: "Global Race Find Trace")
#endif
} else {
@@ -66,7 +66,7 @@ extension GameKitConnectViewController: GKMatchDelegate, GKMatchmakerViewControl
}
}
- // MARK: - GKMatchDelegate
+ // MARK: - GKMatchDelegate -
func match(_ match: GKMatch, didReceive data: Data, fromRemotePlayer player: GKPlayer) {
if isPlayerHost, WKRSeenFinalArticlesStore.isRemoteTransferData(data) {
@@ -87,7 +87,7 @@ extension GameKitConnectViewController: GKMatchDelegate, GKMatchmakerViewControl
}
}
- // MARK: - GKMatchmakerViewControllerDelegate
+ // MARK: - GKMatchmakerViewControllerDelegate -
func matchmakerViewControllerWasCancelled(_ viewController: GKMatchmakerViewController) {
dismiss(animated: true) {
@@ -106,7 +106,7 @@ extension GameKitConnectViewController: GKMatchDelegate, GKMatchmakerViewControl
}
func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFind match: GKMatch) {
- #if !MULTIWINDOWDEBUG
+ #if !MULTIWINDOWDEBUG && !targetEnvironment(macCatalyst)
findTrace?.stop()
#endif
updateDescriptionLabel(to: "Finding best host")
diff --git a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/GameKit/GameKitConnectViewController.swift b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/GameKit/GameKitConnectViewController.swift
index 5585c13..57d49d0 100644
--- a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/GameKit/GameKitConnectViewController.swift
+++ b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/GameKit/GameKitConnectViewController.swift
@@ -11,23 +11,23 @@ import GameKit
import WKRKit
-#if !MULTIWINDOWDEBUG
+#if !MULTIWINDOWDEBUG && !targetEnvironment(macCatalyst)
import FirebasePerformance
#endif
class GameKitConnectViewController: ConnectViewController {
- // MARK: - Properties
+ // MARK: - Properties -
var isPlayerHost = false
var hostPlayerAlias: String?
var match: GKMatch?
- #if !MULTIWINDOWDEBUG
+ #if !MULTIWINDOWDEBUG && !targetEnvironment(macCatalyst)
var findTrace: Trace?
#endif
- // MARK: - View Life Cycle
+ // MARK: - View Life Cycle -
override func viewDidLoad() {
super.viewDidLoad()
@@ -38,7 +38,7 @@ class GameKitConnectViewController: ConnectViewController {
self?.match?.disconnect()
}
- #if !MULTIWINDOWDEBUG
+ #if !MULTIWINDOWDEBUG && !targetEnvironment(macCatalyst)
let playerName = GKLocalPlayer.local.alias
Crashlytics.sharedInstance().setUserName(playerName)
Analytics.setUserProperty(playerName, forName: "playerName")
diff --git a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCConnectViewController/MPCConnectViewController+Invite.swift b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCConnectViewController/MPCConnectViewController+Invite.swift
index 846284a..b509b13 100644
--- a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCConnectViewController/MPCConnectViewController+Invite.swift
+++ b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCConnectViewController/MPCConnectViewController+Invite.swift
@@ -17,7 +17,7 @@ import FirebasePerformance
extension MPCConnectViewController: MCNearbyServiceAdvertiserDelegate, MCSessionDelegate {
- // MARK: - MCSessionDelegate
+ // MARK: - MCSessionDelegate -
func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
func start() {
@@ -28,11 +28,7 @@ extension MPCConnectViewController: MCNearbyServiceAdvertiserDelegate, MCSession
andHide: [inviteView])
}
- // 1. host context is nil when the invite was from a legacy app version (<= 3.6.2)
- // 2. Otherwise, make sure that the host sent the start message
- if hostContext == nil {
- start()
- } else if let object = try? JSONDecoder().decode(StartMessage.self, from: data) {
+ if let object = try? JSONDecoder().decode(StartMessage.self, from: data) {
guard let hostName = hostPeerID?.displayName, object.hostName == hostName else {
let info = "session...didReceive: \(String(describing: hostPeerID?.displayName)), \(object.hostName)"
PlayerAnonymousMetrics.log(event: .error(info))
@@ -56,7 +52,7 @@ extension MPCConnectViewController: MCNearbyServiceAdvertiserDelegate, MCSession
}
})
- #if !MULTIWINDOWDEBUG
+ #if !MULTIWINDOWDEBUG && !targetEnvironment(macCatalyst)
self.connectingTrace?.stop()
self.connectingTrace = nil
#endif
@@ -90,7 +86,7 @@ extension MPCConnectViewController: MCNearbyServiceAdvertiserDelegate, MCSession
updateDescriptionLabel(to: "WAITING FOR INVITE")
}
- // MARK: - MCAdvertiserAssistantDelegate
+ // MARK: - MCAdvertiserAssistantDelegate -
func advertiser(_ advertiser: MCNearbyServiceAdvertiser, didNotStartAdvertisingPeer error: Error) {
let info = "didNotStartAdvertisingPeer: " + error.localizedDescription
@@ -153,7 +149,7 @@ extension MPCConnectViewController: MCNearbyServiceAdvertiserDelegate, MCSession
}
}
- // MARK: - User Actions
+ // MARK: - User Actions -
/// Accepts the displayed invite
@objc
@@ -173,7 +169,7 @@ extension MPCConnectViewController: MCNearbyServiceAdvertiserDelegate, MCSession
stopAdvertising()
- #if !MULTIWINDOWDEBUG
+ #if !MULTIWINDOWDEBUG && !targetEnvironment(macCatalyst)
connectingTrace = Performance.startTrace(name: "Player Connecting Trace")
#endif
}
diff --git a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCConnectViewController/MPCConnectViewController+KB.swift b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCConnectViewController/MPCConnectViewController+KB.swift
index 862dc82..3c35370 100644
--- a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCConnectViewController/MPCConnectViewController+KB.swift
+++ b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCConnectViewController/MPCConnectViewController+KB.swift
@@ -10,7 +10,7 @@ import UIKit
extension MPCConnectViewController {
- // MARK: - Keyboard Support
+ // MARK: - Keyboard Support -
override var keyCommands: [UIKeyCommand]? {
var commands = [
diff --git a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCConnectViewController/MPCConnectViewController+UI.swift b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCConnectViewController/MPCConnectViewController+UI.swift
index 713edd0..0f9b6a8 100644
--- a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCConnectViewController/MPCConnectViewController+UI.swift
+++ b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCConnectViewController/MPCConnectViewController+UI.swift
@@ -10,17 +10,15 @@ import UIKit
extension MPCConnectViewController {
- // MARK: - Interface
+ // MARK: - Interface -
func setupInviteInterface() {
inviteView.alpha = 0.0
- inviteView.backgroundColor = UIColor.wkrBackgroundColor
inviteView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(inviteView)
hostNameLabel.text = ""
hostNameLabel.numberOfLines = 0
- hostNameLabel.textColor = UIColor.wkrLightTextColor
hostNameLabel.textAlignment = .center
hostNameLabel.font = UIFont.systemFont(ofSize: 18, weight: .medium)
hostNameLabel.translatesAutoresizingMaskIntoConstraints = false
diff --git a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCConnectViewController/MPCConnectViewController.swift b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCConnectViewController/MPCConnectViewController.swift
index e64d188..423212a 100644
--- a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCConnectViewController/MPCConnectViewController.swift
+++ b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCConnectViewController/MPCConnectViewController.swift
@@ -13,20 +13,20 @@ import UIKit
import WKRKit
import WKRUIKit
-#if !MULTIWINDOWDEBUG
+#if !MULTIWINDOWDEBUG && !targetEnvironment(macCatalyst)
import FirebasePerformance
#endif
internal class MPCConnectViewController: ConnectViewController {
- // MARK: - Interface Elements
+ // MARK: - Interface Elements -
let inviteView = UIView()
let hostNameLabel = UILabel()
let acceptButton = UIButton()
let declineButton = UIButton()
- // MARK: - Properties
+ // MARK: - Properties -
var playerName = UIDevice.current.name
var isValidPlayerName = false
@@ -34,7 +34,7 @@ internal class MPCConnectViewController: ConnectViewController {
var isPlayerHost = false
var isShowingInvite = false
- // MARK: - MPC Properties
+ // MARK: - MPC Properties -
var advertiser: MCNearbyServiceAdvertiser?
var activeInvite: ((Bool, MCSession) -> Void)?
@@ -51,11 +51,11 @@ internal class MPCConnectViewController: ConnectViewController {
return MCSession(peer: self.peerID)
}()
- #if !MULTIWINDOWDEBUG
+ #if !MULTIWINDOWDEBUG && !targetEnvironment(macCatalyst)
var connectingTrace: Trace?
#endif
- // MARK: - View Life Cycle
+ // MARK: - View Life Cycle -
override func viewDidLoad() {
super.viewDidLoad()
@@ -71,7 +71,7 @@ internal class MPCConnectViewController: ConnectViewController {
PlayerAnonymousMetrics.log(event: .nameType, attributes: ["Type": "DeviceName"])
}
- #if !MULTIWINDOWDEBUG
+ #if !MULTIWINDOWDEBUG && !targetEnvironment(macCatalyst)
Crashlytics.sharedInstance().setUserName(playerName)
Analytics.setUserProperty(playerName, forName: "playerName")
#endif
@@ -82,7 +82,8 @@ internal class MPCConnectViewController: ConnectViewController {
// Uses existing peer ID object if already created (recommended per Apple docs)
if let pastPeerIDData = UserDefaults.standard.data(forKey: "PeerID"),
- let lastPeerID = NSKeyedUnarchiver.unarchiveObject(with: pastPeerIDData) as? MCPeerID,
+ let lastPeerID = try? NSKeyedUnarchiver.unarchivedObject(ofClass: MCPeerID.self,
+ from: pastPeerIDData),
lastPeerID.displayName == playerName {
peerID = lastPeerID
} else {
@@ -91,8 +92,10 @@ internal class MPCConnectViewController: ConnectViewController {
UserDefaults.standard.set(true, forKey: "AttemptingMCPeerIDCreation")
peerID = MCPeerID(displayName: playerName)
UserDefaults.standard.set(false, forKey: "AttemptingMCPeerIDCreation")
- if let peerID = peerID {
- let data = NSKeyedArchiver.archivedData(withRootObject: peerID)
+ if let peerID = peerID,
+ let data = try? NSKeyedArchiver.archivedData(withRootObject: peerID,
+ requiringSecureCoding: true) {
+
UserDefaults.standard.set(data, forKey: "PeerID")
}
}
@@ -152,7 +155,12 @@ internal class MPCConnectViewController: ConnectViewController {
}
}
- // MARK: - State Changes
+ override func viewWillLayoutSubviews() {
+ super.viewWillLayoutSubviews()
+ hostNameLabel.textColor = .wkrSubtitleTextColor(for: traitCollection)
+ }
+
+ // MARK: - State Changes -
func stopAdvertising() {
advertiser?.stopAdvertisingPeer()
@@ -189,7 +197,11 @@ internal class MPCConnectViewController: ConnectViewController {
}
}
- let nav = UINavigationController(rootViewController: controller)
+ let nav = WKRUINavigationController(rootViewController: controller)
+ nav.modalPresentationStyle = .fullScreen
+ if #available(iOS 13.0, *) {
+ nav.isModalInPresentation = true
+ }
present(nav, animated: true, completion: nil)
}
diff --git a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/Cells/MPCHostAutoInviteCell.swift b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/Cells/MPCHostAutoInviteCell.swift
new file mode 100644
index 0000000..eb2b1c8
--- /dev/null
+++ b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/Cells/MPCHostAutoInviteCell.swift
@@ -0,0 +1,96 @@
+//
+// MPCHostAutoInviteCell.swift
+// WikiRaces
+//
+// Created by Andrew Finke on 11/6/19.
+// Copyright © 2019 Andrew Finke. All rights reserved.
+//
+
+import UIKit
+import WKRUIKit
+
+internal class MPCHostAutoInviteCell: UITableViewCell {
+
+ // MARK: - Properties
+
+ var onToggle: ((Bool) -> Void)?
+ var isEnabled: Bool = false {
+ didSet {
+ toggle.isOn = isEnabled
+ onToggle?(isEnabled)
+ }
+ }
+
+ private let detailLabel = UILabel()
+ private let toggle = UISwitch()
+
+ static let reuseIdentifier = "hostAutoInviteCell"
+
+ // MARK: - Initialization
+
+ override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
+ super.init(style: style, reuseIdentifier: reuseIdentifier)
+
+ selectionStyle = .none
+
+ detailLabel.text = "Auto-Invite"
+ detailLabel.textAlignment = .left
+ detailLabel.font = UIFont.systemFont(ofSize: 17, weight: .regular)
+ detailLabel.numberOfLines = 0
+ detailLabel.translatesAutoresizingMaskIntoConstraints = false
+ addSubview(detailLabel)
+
+ toggle.onTintColor = .lightGray
+ toggle.addTarget(self, action: #selector(toggled), for: .valueChanged)
+ toggle.translatesAutoresizingMaskIntoConstraints = false
+ addSubview(toggle)
+
+ let leftMarginConstraint = NSLayoutConstraint(item: detailLabel,
+ attribute: .left,
+ relatedBy: .equal,
+ toItem: self,
+ attribute: .leftMargin,
+ multiplier: 1.0,
+ constant: 0.0)
+
+ let rightMarginConstraint = NSLayoutConstraint(item: toggle,
+ attribute: .right,
+ relatedBy: .equal,
+ toItem: self,
+ attribute: .rightMargin,
+ multiplier: 1.0,
+ constant: 0.0)
+
+ let constraints = [
+ leftMarginConstraint,
+ detailLabel.topAnchor.constraint(equalTo: topAnchor, constant: 10),
+ detailLabel.rightAnchor.constraint(lessThanOrEqualTo: toggle.leftAnchor,
+ constant: -10),
+ detailLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10),
+
+ rightMarginConstraint,
+ toggle.centerYAnchor.constraint(equalTo: centerYAnchor)
+ ]
+ NSLayoutConstraint.activate(constraints)
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ // MARK: - View Life Cycle -
+
+ public override func layoutSubviews() {
+ super.layoutSubviews()
+ let textColor = UIColor.wkrTextColor(for: traitCollection)
+ detailLabel.textColor = textColor
+ }
+
+ // MARK: - Helpers -
+
+ @objc
+ func toggled() {
+ isEnabled = toggle.isOn
+ UISelectionFeedbackGenerator().selectionChanged()
+ }
+}
diff --git a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/Cells/MPCHostPeerStateCell.swift b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/Cells/MPCHostPeerStateCell.swift
index 1d3a88c..3776bc2 100644
--- a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/Cells/MPCHostPeerStateCell.swift
+++ b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/Cells/MPCHostPeerStateCell.swift
@@ -22,9 +22,6 @@ internal class MPCHostPeerStateCell: UITableViewCell {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
- backgroundColor = UIColor.wkrBackgroundColor
-
- peerLabel.textColor = UIColor.wkrTextColor
peerLabel.textAlignment = .left
peerLabel.font = UIFont.systemFont(ofSize: 17, weight: .regular)
peerLabel.numberOfLines = 0
@@ -32,7 +29,6 @@ internal class MPCHostPeerStateCell: UITableViewCell {
addSubview(peerLabel)
detailLabel.textAlignment = .right
- detailLabel.textColor = UIColor.wkrTextColor
detailLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
detailLabel.translatesAutoresizingMaskIntoConstraints = false
addSubview(detailLabel)
@@ -57,7 +53,8 @@ internal class MPCHostPeerStateCell: UITableViewCell {
leftMarginConstraint,
peerLabel.topAnchor.constraint(equalTo: topAnchor, constant: 10),
peerLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 25),
- peerLabel.rightAnchor.constraint(lessThanOrEqualTo: detailLabel.leftAnchor, constant: -10),
+ peerLabel.rightAnchor.constraint(lessThanOrEqualTo: detailLabel.leftAnchor,
+ constant: -10),
peerLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10),
rightMarginConstraint,
@@ -69,4 +66,14 @@ internal class MPCHostPeerStateCell: UITableViewCell {
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
+
+ // MARK: - View Life Cycle -
+
+ public override func layoutSubviews() {
+ super.layoutSubviews()
+ let textColor = UIColor.wkrTextColor(for: traitCollection)
+ peerLabel.textColor = textColor
+ detailLabel.textColor = textColor
+ }
+
}
diff --git a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/Cells/MPCHostSearchingCell.swift b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/Cells/MPCHostSearchingCell.swift
index 53d5d54..b2e1862 100644
--- a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/Cells/MPCHostSearchingCell.swift
+++ b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/Cells/MPCHostSearchingCell.swift
@@ -10,19 +10,18 @@ import UIKit
internal class MPCHostSearchingCell: UITableViewCell {
- // MARK: - Properties
+ // MARK: - Properties -
private var dots: Int = 3
private var timer: Timer?
static let reuseIdentifier = "searchingCell"
- // MARK: - Initialization
+ // MARK: - Initialization -
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
isUserInteractionEnabled = false
- backgroundColor = UIColor.wkrBackgroundColor
textLabel?.textColor = UIColor(red: 184.0 / 255.0,
green: 184.0 / 255.0,
blue: 184.0 / 255.0,
@@ -38,7 +37,7 @@ internal class MPCHostSearchingCell: UITableViewCell {
super.init(coder: aDecoder)
}
- // MARK: - Helpers
+ // MARK: - Helpers -
func updateText() {
dots += 1
diff --git a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/Cells/MPCHostSoloCell.swift b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/Cells/MPCHostSoloCell.swift
index adc4e57..7a21c54 100644
--- a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/Cells/MPCHostSoloCell.swift
+++ b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/Cells/MPCHostSoloCell.swift
@@ -18,7 +18,6 @@ internal class MPCHostSoloCell: UITableViewCell {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
- backgroundColor = UIColor.wkrBackgroundColor
textLabel?.text = "Solo Race"
textLabel?.textColor = UIColor(red: 0,
green: 122.0 / 255.0,
diff --git a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/MPCHostViewController+Table.swift b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/MPCHostViewController+Table.swift
index 407ca45..5acfb81 100644
--- a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/MPCHostViewController+Table.swift
+++ b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/MPCHostViewController+Table.swift
@@ -15,7 +15,7 @@ extension MPCHostViewController {
// MARK: - UITableViewDataSource
override func numberOfSections(in tableView: UITableView) -> Int {
- return 2
+ return 3
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
@@ -33,6 +33,8 @@ extension MPCHostViewController {
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section == 0 {
return "Choose 1 to 7 players"
+ } else if section == 1 {
+ return nil
} else {
return " "
}
@@ -42,6 +44,8 @@ extension MPCHostViewController {
if section == 0 {
//swiftlint:disable:next line_length
return "Make sure all players are on the same Wi-Fi network and have Bluetooth enabled for the best results."
+ } else if section == 1 {
+ return "Automatically invite nearby players to the race."
} else {
return "Practice your skills in solo races. Solo races will not count towards your stats."
}
@@ -49,6 +53,17 @@ extension MPCHostViewController {
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 1 {
+ guard let cell = tableView.dequeueReusableCell(withIdentifier: MPCHostAutoInviteCell.reuseIdentifier,
+ for: indexPath) as? MPCHostAutoInviteCell else {
+ fatalError()
+ }
+ cell.isEnabled = isAutoInviteOn
+ cell.onToggle = { [weak self] toggle in
+ self?.isAutoInviteOn = toggle
+ PlayerAnonymousMetrics.log(event: .autoInviteToggled)
+ }
+ return cell
+ } else if indexPath.section == 2 {
return tableView.dequeueReusableCell(withIdentifier: MPCHostSoloCell.reuseIdentifier,
for: indexPath)
} else if peers.isEmpty {
@@ -78,9 +93,11 @@ extension MPCHostViewController {
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+ if indexPath.section == 1 { return }
+
PlayerAnonymousMetrics.log(event: .userAction(#function))
- if indexPath.section == 1 {
+ if indexPath.section == 2 {
PlayerAnonymousMetrics.log(event: .hostStartedSoloMatch)
session?.disconnect()
@@ -92,16 +109,29 @@ extension MPCHostViewController {
// Hits this case when the "Searching..." placeholder cell is selected
guard !peers.isEmpty else { return }
- let maxPlayerCount = min(WKRKitConstants.current.maxLocalRacePlayers,
- kMCSessionMaximumNumberOfPeers)
- let peerCount = session?.connectedPeers.count ?? 0
- guard maxPlayerCount > peerCount + 1 else { return }
-
let peerID = sortedPeers[indexPath.row]
+ invite(peerID: peerID)
+
+ tableView.deselectRow(at: indexPath, animated: true)
+ }
+
+ override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
+ if (indexPath.section == 0 && peers.isEmpty) || indexPath.section == 1 {
+ return 44.0
+ }
+ return super.tableView(tableView, heightForRowAt: indexPath)
+ }
+
+ func invite(peerID: MCPeerID) {
guard let session = session else {
fatalError("Session is nil")
}
+ let maxPlayerCount = min(WKRKitConstants.current.maxLocalRacePlayers,
+ kMCSessionMaximumNumberOfPeers)
+ let peerCount = session.connectedPeers.count
+ guard maxPlayerCount > peerCount + 1 else { return }
+
if session.connectedPeers.map({ $0.displayName }).contains(peerID.displayName) {
let alertController = UIAlertController(title: "Duplicate Name",
message: "Player has the same name as another player in the match.",
@@ -126,14 +156,6 @@ extension MPCHostViewController {
to: session,
withContext: data,
timeout: context.inviteTimeout)
- tableView.deselectRow(at: indexPath, animated: true)
- }
-
- override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
- if (indexPath.section == 0 && peers.isEmpty) || indexPath.section == 1 {
- return 44.0
- }
- return super.tableView(tableView, heightForRowAt: indexPath)
}
}
diff --git a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/MPCHostViewController.swift b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/MPCHostViewController.swift
index 89a736f..0c55929 100644
--- a/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/MPCHostViewController.swift
+++ b/WikiRaces/Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostViewController/MPCHostViewController.swift
@@ -12,13 +12,13 @@ import UIKit
import WKRKit
import WKRUIKit
-#if !MULTIWINDOWDEBUG
+#if !MULTIWINDOWDEBUG && !targetEnvironment(macCatalyst)
import FirebasePerformance
#endif
internal class MPCHostViewController: UITableViewController, MCSessionDelegate, MCNearbyServiceBrowserDelegate {
- // MARK: - Types
+ // MARK: - Types -
enum PeerState: String {
case found
@@ -32,7 +32,7 @@ internal class MPCHostViewController: UITableViewController, MCSessionDelegate,
case startMatch(isSolo: Bool)
case cancel
}
- // MARK: - Properties
+ // MARK: - Properties -
var peers = [MCPeerID: PeerState]()
var sortedPeers: [MCPeerID] {
@@ -41,7 +41,7 @@ internal class MPCHostViewController: UITableViewController, MCSessionDelegate,
})
}
- #if !MULTIWINDOWDEBUG
+ #if !MULTIWINDOWDEBUG && !targetEnvironment(macCatalyst)
var peersConnectTraces = [MCPeerID: Trace]()
#endif
@@ -50,13 +50,28 @@ internal class MPCHostViewController: UITableViewController, MCSessionDelegate,
var serviceType: String?
var browser: MCNearbyServiceBrowser?
+ private static let isAutoInviteOnKey = "isAutoInviteOnKey"
+ var isAutoInviteOn = UserDefaults.standard.bool(forKey: MPCHostViewController.isAutoInviteOnKey) {
+ didSet {
+ UserDefaults.standard.set(isAutoInviteOn, forKey: MPCHostViewController.isAutoInviteOnKey)
+ if isAutoInviteOn {
+ peers.forEach { peerID, state in
+ if state == PeerState.found {
+ self.invite(peerID: peerID)
+ }
+ }
+ }
+ }
+ }
+
var listenerUpdate: ((ListenerUpdate) -> Void)?
+ private let activityView = UIActivityIndicatorView(style: .gray)
- // MARK: - View Life Cycle
+ // MARK: - View Life Cycle -
override func viewDidLoad() {
super.viewDidLoad()
- title = "INVITE NEARBY PLAYERS"
+ title = "CREATE LOCAL RACE"
guard let peerID = peerID, let serviceType = serviceType else {
fatalError("Required properties peerID or serviceType not set")
@@ -74,9 +89,6 @@ internal class MPCHostViewController: UITableViewController, MCSessionDelegate,
action: #selector(startMatch(_:)))
startButton.isEnabled = false
navigationItem.rightBarButtonItem = startButton
- navigationController?.navigationBar.barStyle = UIBarStyle.wkrStyle
-
- tableView.backgroundColor = WKRUIStyle.isDark ? UIColor.wkrBackgroundColor : UIColor.groupTableViewBackground
tableView.estimatedRowHeight = 150
tableView.rowHeight = UITableView.automaticDimension
@@ -84,8 +96,13 @@ internal class MPCHostViewController: UITableViewController, MCSessionDelegate,
forCellReuseIdentifier: MPCHostPeerStateCell.reuseIdentifier)
tableView.register(MPCHostSearchingCell.self,
forCellReuseIdentifier: MPCHostSearchingCell.reuseIdentifier)
+ tableView.register(MPCHostAutoInviteCell.self,
+ forCellReuseIdentifier: MPCHostAutoInviteCell.reuseIdentifier)
tableView.register(MPCHostSoloCell.self,
forCellReuseIdentifier: MPCHostSoloCell.reuseIdentifier)
+
+ PlayerAnonymousMetrics.log(event: .autoInviteState,
+ attributes: ["On": isAutoInviteOn ? 1 : 0])
}
override func viewWillAppear(_ animated: Bool) {
@@ -100,7 +117,12 @@ internal class MPCHostViewController: UITableViewController, MCSessionDelegate,
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}
- // MARK: - Actions
+ override func viewWillLayoutSubviews() {
+ super.viewWillLayoutSubviews()
+ activityView.color = .wkrActivityIndicatorColor(for: traitCollection)
+ }
+
+ // MARK: - Actions -
@objc
func cancelMatch(_ sender: Any) {
@@ -117,8 +139,6 @@ internal class MPCHostViewController: UITableViewController, MCSessionDelegate,
tableView.isUserInteractionEnabled = false
- let activityView = UIActivityIndicatorView(style: .gray)
- activityView.color = UIColor.wkrActivityIndicatorColor
activityView.sizeToFit()
activityView.startAnimating()
@@ -183,13 +203,13 @@ internal class MPCHostViewController: UITableViewController, MCSessionDelegate,
tableView.reloadData()
}
}
- navigationItem.rightBarButtonItem?.isEnabled = !peers.values.filter({ $0 == .joined }).isEmpty
-
+ let joinedPlayers: [MCPeerID: PeerState] = peers.filter({ $0.value == .joined })
+ navigationItem.rightBarButtonItem?.isEnabled = !joinedPlayers.isEmpty
performaceTrace(peerID: peerID, newState: newState)
}
func performaceTrace(peerID: MCPeerID, newState: PeerState?) {
- #if !MULTIWINDOWDEBUG
+ #if !MULTIWINDOWDEBUG && !targetEnvironment(macCatalyst)
let hostInviteResponseTraceName = "Host Invite Response Trace"
let hostInviteJoingTraceName = "Host Invite Joining Trace"
@@ -214,7 +234,7 @@ internal class MPCHostViewController: UITableViewController, MCSessionDelegate,
#endif
}
- // MARK: - MCNearbyServiceBrowserDelegate
+ // MARK: - MCNearbyServiceBrowserDelegate -
func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) {
DispatchQueue.main.async {
@@ -236,10 +256,13 @@ internal class MPCHostViewController: UITableViewController, MCSessionDelegate,
withDiscoveryInfo info: [String: String]?) {
DispatchQueue.main.async {
self.update(peerID: peerID, to: .found)
+ if self.isAutoInviteOn {
+ self.invite(peerID: peerID)
+ }
}
}
- // MARK: - MCSessionDelegate
+ // MARK: - MCSessionDelegate -
func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) {
DispatchQueue.main.async {
@@ -264,7 +287,7 @@ internal class MPCHostViewController: UITableViewController, MCSessionDelegate,
WKRSeenFinalArticlesStore.addRemoteTransferData(data)
}
- // MARK: - Unused MCSessionDelegate
+ // MARK: - Unused MCSessionDelegate -
func session(_ session: MCSession,
didReceive stream: InputStream,
diff --git a/WikiRaces/Shared/Menu View Controllers/DebugInfoTableViewController/DebugInfoTableViewController.swift b/WikiRaces/Shared/Menu View Controllers/DebugInfoTableViewController/DebugInfoTableViewController.swift
index 42cbb29..600c8a8 100644
--- a/WikiRaces/Shared/Menu View Controllers/DebugInfoTableViewController/DebugInfoTableViewController.swift
+++ b/WikiRaces/Shared/Menu View Controllers/DebugInfoTableViewController/DebugInfoTableViewController.swift
@@ -24,7 +24,6 @@ class DebugInfoTableViewController: UITableViewController {
tableView.register(DebugInfoTableViewCell.self,
forCellReuseIdentifier: DebugInfoTableViewCell.reuseIdentifier)
- navigationController?.navigationBar.barStyle = UIBarStyle.wkrStyle
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action,
target: self,
action: #selector(share(_:)))
diff --git a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MedalScene.swift b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MedalScene.swift
index 9065e14..44ec698 100644
--- a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MedalScene.swift
+++ b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MedalScene.swift
@@ -10,7 +10,7 @@ import SpriteKit
class MedalScene: SKScene {
- // MARK: Properties
+ // MARK: Properties -
private let goldNode: SKNode
private let silverNode: SKNode
@@ -23,7 +23,7 @@ class MedalScene: SKScene {
}
}
- // MARK: - Initalization
+ // MARK: - Initalization -
override init(size: CGSize) {
let physicsBody = SKPhysicsBody(circleOfRadius: 5)
@@ -69,7 +69,7 @@ class MedalScene: SKScene {
fatalError("init(coder:) has not been implemented")
}
- // MARK: - Update
+ // MARK: - Update -
override func update(_ currentTime: TimeInterval) {
for node in children where node.position.y < -50 {
@@ -80,7 +80,7 @@ class MedalScene: SKScene {
}
}
- // MARK: - Other
+ // MARK: - Other -
func showMedals(gold: Int, silver: Int, bronze: Int, dnf: Int) {
func createMedal(place: Int) {
diff --git a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MedalView.swift b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MedalView.swift
index 19bae60..9aba238 100644
--- a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MedalView.swift
+++ b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MedalView.swift
@@ -10,11 +10,11 @@ import SpriteKit
class MedalView: SKView {
- // MARK: - Properties
+ // MARK: - Properties -
- let medalScene = MedalScene(size: .zero)
+ private let medalScene = MedalScene(size: .zero)
- // MARK: - Initalization
+ // MARK: - Initalization -
init() {
super.init(frame: .zero)
@@ -30,7 +30,7 @@ class MedalView: SKView {
fatalError("init(coder:) has not been implemented")
}
- // MARK: - View Life Cycle
+ // MARK: - View Life Cycle -
override func layoutSubviews() {
super.layoutSubviews()
diff --git a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MenuTile.swift b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MenuTile.swift
index e06ac52..b7bd10d 100644
--- a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MenuTile.swift
+++ b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MenuTile.swift
@@ -7,10 +7,11 @@
//
import UIKit
+import WKRUIKit
internal class MenuTile: UIControl {
- // MARK: - Properties
+ // MARK: - Properties -
/// Used for displaying the stat number (i.e. 3.33333 to 3.33)
static private let numberFormatter: NumberFormatter = {
@@ -48,8 +49,7 @@ internal class MenuTile: UIControl {
}
titleLabel.attributedText = NSAttributedString(string: text,
spacing: 3.0,
- font: titleLabel.font,
- textColor: UIColor.wkrTextColor)
+ font: titleLabel.font)
}
get {
return titleLabel.attributedText?.string
@@ -93,7 +93,7 @@ internal class MenuTile: UIControl {
}
}
- // MARK: - Initialization
+ // MARK: - Initialization -
/// Init with the tile's title
///
@@ -108,7 +108,6 @@ internal class MenuTile: UIControl {
titleLabel.translatesAutoresizingMaskIntoConstraints = false
addSubview(titleLabel)
- valueLabel.textColor = UIColor.wkrTextColor
valueLabel.adjustsFontSizeToFitWidth = true
valueLabel.translatesAutoresizingMaskIntoConstraints = false
addSubview(valueLabel)
@@ -131,4 +130,13 @@ internal class MenuTile: UIControl {
fatalError("init(coder:) has not been implemented")
}
+ // MARK: - View Life Cycle -
+
+ public override func layoutSubviews() {
+ super.layoutSubviews()
+ let textColor: UIColor = .wkrTextColor(for: traitCollection)
+ titleLabel.textColor = textColor
+ valueLabel.textColor = textColor
+ }
+
}
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 48cecaf..e29ca68 100644
--- a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MenuView+Actions.swift
+++ b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MenuView+Actions.swift
@@ -11,7 +11,7 @@ import GameKit.GKLocalPlayer
extension MenuView {
- // MARK: - Actions
+ // MARK: - Actions -
/// Join button pressed
@objc
@@ -20,7 +20,6 @@ extension MenuView {
PlayerAnonymousMetrics.log(event: .pressedLocalOptions)
UISelectionFeedbackGenerator().selectionChanged()
-
animateOptionsOutAndTransition(to: .localOptions)
}
@@ -32,7 +31,7 @@ extension MenuView {
UISelectionFeedbackGenerator().selectionChanged()
- guard GKLocalPlayer.local.isAuthenticated else {
+ guard GKLocalPlayer.local.isAuthenticated || UserDefaults.standard.bool(forKey: "FASTLANE_SNAPSHOT") else {
self.listenerUpdate?(.presentGlobalAuth)
return
}
@@ -109,7 +108,7 @@ extension MenuView {
medalView.showMedals()
}
- // MARK: - Menu Animations
+ // MARK: - Menu Animations -
/// Animates the views on screen
func animateMenuIn(completion: (() -> Void)? = nil) {
diff --git a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MenuView+Setup.swift b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MenuView+Setup.swift
index 3b2b7b1..c60d931 100644
--- a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MenuView+Setup.swift
+++ b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MenuView+Setup.swift
@@ -11,7 +11,7 @@ import WKRUIKit
extension MenuView {
- // MARK: - Top View
+ // MARK: - Top View -
/// Sets up the top view of the menu
//swiftlint:disable:next function_body_length
@@ -108,40 +108,27 @@ extension MenuView {
topView.addSubview(createLocalRaceButton)
localOptionsBackButton.setImage(UIImage(named: "Back")!, for: .normal)
- localOptionsBackButton.tintColor = .wkrTextColor
localOptionsBackButton.translatesAutoresizingMaskIntoConstraints = false
localOptionsBackButton.addTarget(self, action: #selector(localOptionsBackButtonPressed), for: .touchUpInside)
topView.addSubview(localOptionsBackButton)
localOptionsBackButton.layer.borderWidth = 1.7
- localOptionsBackButton.layer.borderColor = UIColor.wkrTextColor.cgColor
- }
+ }
/// Sets up the labels
private func setupLabels() {
titleLabel.text = "WikiRaces"
- titleLabel.textColor = UIColor.wkrTextColor
titleLabel.translatesAutoresizingMaskIntoConstraints = false
topView.addSubview(titleLabel)
- #if DEBUG
- if !UserDefaults.standard.bool(forKey: "FASTLANE_SNAPSHOT") {
- titleLabel.textColor = UIColor(red: 51.0 / 255.0,
- green: 102.0 / 255.0,
- blue: 204.0 / 255.0,
- alpha: 1.0)
- }
- #endif
-
subtitleLabel.text = "Conquer the encyclopedia\nof everything."
subtitleLabel.numberOfLines = 2
- subtitleLabel.textColor = UIColor.wkrTextColor
subtitleLabel.translatesAutoresizingMaskIntoConstraints = false
subtitleLabel.clipsToBounds = true
topView.addSubview(subtitleLabel)
}
- // MARK: - Bottom View
+ // MARK: - Bottom View -
/// Sets up the bottom views
func setupBottomView() {
diff --git a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MenuView.swift b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MenuView.swift
index 8601a7f..72efbcc 100644
--- a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MenuView.swift
+++ b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MenuView.swift
@@ -95,9 +95,6 @@ class MenuView: UIView {
init() {
super.init(frame: .zero)
- backgroundColor = UIColor.wkrBackgroundColor
- UIApplication.shared.keyWindow?.backgroundColor = UIColor.wkrBackgroundColor
-
let recognizer = UITapGestureRecognizer(target: self, action: #selector(tapGestureRecognizerFired))
recognizer.numberOfTapsRequired = 2
recognizer.numberOfTouchesRequired = 2
@@ -105,10 +102,8 @@ class MenuView: UIView {
titleLabel.isUserInteractionEnabled = true
topView.translatesAutoresizingMaskIntoConstraints = false
- topView.backgroundColor = UIColor.wkrMenuTopViewColor
addSubview(topView)
- bottomView.backgroundColor = UIColor.wkrMenuBottomViewColor
bottomView.translatesAutoresizingMaskIntoConstraints = false
addSubview(bottomView)
@@ -152,6 +147,14 @@ class MenuView: UIView {
override func layoutSubviews() {
super.layoutSubviews()
+ bottomView.backgroundColor = .wkrMenuBottomViewColor(for: traitCollection)
+
+ let textColor: UIColor = .wkrTextColor(for: traitCollection)
+ titleLabel.textColor = textColor
+ subtitleLabel.textColor = textColor
+ localOptionsBackButton.tintColor = textColor
+ localOptionsBackButton.layer.borderColor = textColor.cgColor
+
// Button Styles
let buttonStyle: WKRUIButtonStyle
diff --git a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MovingPuzzleView.swift b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MovingPuzzleView.swift
index 8bbe332..5cca65d 100644
--- a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MovingPuzzleView.swift
+++ b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuView/MovingPuzzleView.swift
@@ -17,7 +17,6 @@ class MovingPuzzleView: UIView, UIScrollViewDelegate {
init() {
super.init(frame: .zero)
- backgroundColor = UIColor.wkrMenuPuzzleViewColor
translatesAutoresizingMaskIntoConstraints = false
innerPuzzleView.delegate = self
@@ -50,6 +49,15 @@ class MovingPuzzleView: UIView, UIScrollViewDelegate {
fatalError("init(coder:) has not been implemented")
}
+ // MARK: - View Life Cycle -
+
+ public override func layoutSubviews() {
+ super.layoutSubviews()
+ backgroundColor = .wkrMenuPuzzleViewColor(for: traitCollection)
+ }
+
+ // MARK: - UIScrollViewDelegate -
+
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let contentOffset = innerPuzzleView.contentOffset.x
if contentOffset > innerPuzzleView.contentSize.width * 0.8 {
@@ -58,6 +66,8 @@ class MovingPuzzleView: UIView, UIScrollViewDelegate {
PlayerAnonymousMetrics.log(event: .puzzleViewScrolled)
}
+ // MARK: - Helpers -
+
private func animateContentOffsetReset() {
UIView.animate(withDuration: 0.25,
animations: {
diff --git a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuViewController+Debug.swift b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuViewController+Debug.swift
index 7b8c325..23a8a3d 100644
--- a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuViewController+Debug.swift
+++ b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuViewController+Debug.swift
@@ -22,12 +22,6 @@ extension MenuViewController {
message: message,
preferredStyle: .alert)
- let darkAction = UIAlertAction(title: "Toggle Dark UI", style: .default, handler: { _ in
- WKRUIStyle.isDark = !WKRUIStyle.isDark
- exit(1998)
- })
- alertController.addAction(darkAction)
-
let buildAction = UIAlertAction(title: "Show Build Info", style: .default, handler: { _ in
self.showDebugBuildInfo()
})
@@ -49,7 +43,7 @@ extension MenuViewController {
let appBundleInfo = Bundle.main.infoDictionary
let kitBundleInfo = Bundle(for: WKRGameManager.self).infoDictionary
- let interfaceBundleInfo = Bundle(for: WKRUIStyle.self).infoDictionary
+ let interfaceBundleInfo = Bundle(for: WKRUIWebView.self).infoDictionary
guard let appBundleVersion = appBundleInfo?[versionKey] as? String,
let appBundleShortVersion = appBundleInfo?[shortVersionKey] as? String,
@@ -71,7 +65,7 @@ extension MenuViewController {
("WKRUIKit Constants Version", "\(WKRUIKitConstants.current.version)")
]
- let navController = UINavigationController(rootViewController: debugInfoController)
+ let navController = WKRUINavigationController(rootViewController: debugInfoController)
present(navController, animated: true, completion: nil)
}
@@ -85,7 +79,7 @@ extension MenuViewController {
return lhs.key.lowercased() < rhs.key.lowercased()
}
- let navController = UINavigationController(rootViewController: debugInfoController)
+ let navController = WKRUINavigationController(rootViewController: debugInfoController)
present(navController, animated: true, completion: nil)
}
}
diff --git a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuViewController+GameKit.swift b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuViewController+GameKit.swift
index e9280d3..a2b95f1 100644
--- a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuViewController+GameKit.swift
+++ b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuViewController+GameKit.swift
@@ -10,11 +10,12 @@ import GameKit
extension MenuViewController: GKGameCenterControllerDelegate {
- // MARK: - Game Center
+ // MARK: - Game Center -
/// Attempts Game Center login
func attemptGlobalAuthentication() {
- GlobalRaceHelper.shared.authenticate { controller, error, forceShowError in
+ // seperated due to long type-checking time as closure
+ func auth(_ controller: UIViewController?, _ error: Error?, _ forceShowError: Bool) {
if let controller = controller, self.menuView.state != .noInterface {
if self.presentedViewController == nil {
self.present(controller, animated: true, completion: nil)
@@ -32,9 +33,10 @@ extension MenuViewController: GKGameCenterControllerDelegate {
PlayerAnonymousMetrics.log(event: .error(info))
}
}
+ GlobalRaceHelper.shared.authenticate(completion: auth)
}
- // MARK: - GKGameCenterControllerDelegate
+ // MARK: - GKGameCenterControllerDelegate -
func gameCenterViewControllerDidFinish(_ gameCenterViewController: GKGameCenterViewController) {
PlayerAnonymousMetrics.log(event: .userAction(#function))
@@ -43,7 +45,7 @@ extension MenuViewController: GKGameCenterControllerDelegate {
}
}
- // MARK: - Other
+ // MARK: - Other -
func presentGameKitAuthAlert() {
let title = "Global Races Unavailable"
diff --git a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuViewController+KB.swift b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuViewController+KB.swift
index c1c357f..32d1473 100644
--- a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuViewController+KB.swift
+++ b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuViewController+KB.swift
@@ -10,7 +10,7 @@ import UIKit
extension MenuViewController {
- // MARK: - Keyboard Support
+ // MARK: - Keyboard Support -
override var keyCommands: [UIKeyCommand]? {
return [
diff --git a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuViewController.swift b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuViewController.swift
index 8fdfab6..0a13f65 100644
--- a/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuViewController.swift
+++ b/WikiRaces/Shared/Menu View Controllers/MenuViewController/MenuViewController.swift
@@ -16,7 +16,7 @@ import WKRUIKit
/// The main menu view controller
internal class MenuViewController: UIViewController {
- // MARK: - View
+ // MARK: - View -
override func loadView() {
view = MenuView()
@@ -28,11 +28,9 @@ internal class MenuViewController: UIViewController {
}
private var isFirstAppearence = true
-
override var canBecomeFirstResponder: Bool { return true }
- override var preferredStatusBarStyle: UIStatusBarStyle { return .wkrStatusBarStyle }
- // MARK: - View Life Cycle
+ // MARK: - View Life Cycle -
override func viewDidLoad() {
super.viewDidLoad()
@@ -93,7 +91,7 @@ internal class MenuViewController: UIViewController {
#if MULTIWINDOWDEBUG
let controller = GameViewController()
- let nav = UINavigationController(rootViewController: controller)
+ let nav = WKRUINavigationController(rootViewController: controller)
let name = (view.window as? DebugWindow)?.playerName ?? ""
controller.networkConfig = .multiwindow(windowName: name,
isHost: view.window!.frame.origin == .zero)
@@ -115,13 +113,19 @@ internal class MenuViewController: UIViewController {
becomeFirstResponder()
}
+ override func viewWillLayoutSubviews() {
+ super.viewWillLayoutSubviews()
+ let mode = WKRUIStyle.isDark(traitCollection) ? 1 : 0
+ PlayerAnonymousMetrics.log(event: .interfaceMode, attributes: ["Dark": mode])
+ }
+
override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
if motion == .motionShake {
menuView.triggeredEasterEgg()
}
}
- // MARK: - Name Checking
+ // MARK: - Name Checking -
func promptForInvalidName() {
guard UserDefaults.standard.bool(forKey: "AttemptingMCPeerIDCreation") else {
@@ -147,7 +151,7 @@ internal class MenuViewController: UIViewController {
present(alertController, animated: true, completion: nil)
}
- // MARK: - Other
+ // MARK: - Other -
func presentMPCConnect(isHost: Bool) {
UIApplication.shared.isIdleTimerDisabled = true
@@ -160,9 +164,8 @@ internal class MenuViewController: UIViewController {
func presentGlobalConnect() {
if UserDefaults.standard.bool(forKey: "FASTLANE_SNAPSHOT") {
let controller = GameViewController()
- let nav = UINavigationController(rootViewController: controller)
- let url = URL(string: "https://en.m.wikipedia.org/wiki/Walt_Disney_World")!
- controller.prepareForScreenshots(for: url)
+ let nav = WKRUINavigationController(rootViewController: controller)
+ nav.modalPresentationStyle = .overCurrentContext
present(nav, animated: true, completion: nil)
} else if GKLocalPlayer.local.isAuthenticated {
UIApplication.shared.isIdleTimerDisabled = true
diff --git a/WikiRaces/Shared/Other/GlobalRacesHelper.swift b/WikiRaces/Shared/Other/GlobalRacesHelper.swift
index d16bd37..f722f76 100644
--- a/WikiRaces/Shared/Other/GlobalRacesHelper.swift
+++ b/WikiRaces/Shared/Other/GlobalRacesHelper.swift
@@ -10,14 +10,14 @@ import GameKit
class GlobalRaceHelper: NSObject, GKLocalPlayerListener {
- // MARK: - Properties
+ // MARK: - Properties -
static let shared = GlobalRaceHelper()
var lastInvite: GKInvite?
var isHandlerSetup = false
var didReceiveInvite: (() -> Void)?
- // MARK: - Helpers
+ // MARK: - Helpers -
func authenticate(completion: ((UIViewController?, Error?, _ forceShowErrorMessage: Bool) -> Void)?) {
guard !UserDefaults.standard.bool(forKey: "FASTLANE_SNAPSHOT") else {
@@ -40,7 +40,7 @@ class GlobalRaceHelper: NSObject, GKLocalPlayerListener {
}
}
- // MARK: - GKLocalPlayerListener
+ // MARK: - GKLocalPlayerListener -
func player(_ player: GKPlayer, didAccept invite: GKInvite) {
PlayerDatabaseStat.gkInvitedToMatch.increment()
diff --git a/WikiRaces/Shared/Other/UIFont+Rounded.swift b/WikiRaces/Shared/Other/UIFont+Rounded.swift
new file mode 100644
index 0000000..bd19380
--- /dev/null
+++ b/WikiRaces/Shared/Other/UIFont+Rounded.swift
@@ -0,0 +1,23 @@
+//
+// UIFont+Rounded.swift
+// magic.world
+//
+// Created by Andrew Finke on 10/26/19.
+// Copyright © 2019 Andrew Finke. All rights reserved.
+//
+
+import UIKit
+
+extension UIFont {
+ static func systemRoundedFont(ofSize size: CGFloat, weight: UIFont.Weight) -> UIFont? {
+ if #available(iOS 13.0, *) {
+ let font = UIFont.systemFont(ofSize: size, weight: weight)
+ guard let descriptor = font.fontDescriptor.withDesign(.rounded) else {
+ fatalError()
+ }
+ return UIFont(descriptor: descriptor, size: size)
+ } else {
+ return nil
+ }
+ }
+}
diff --git a/WikiRaces/Shared/Other/WKRAppDelegate.swift b/WikiRaces/Shared/Other/WKRAppDelegate.swift
index e498fd9..c39da10 100644
--- a/WikiRaces/Shared/Other/WKRAppDelegate.swift
+++ b/WikiRaces/Shared/Other/WKRAppDelegate.swift
@@ -14,7 +14,7 @@ import WKRUIKit
internal class WKRAppDelegate: UIResponder, UIApplicationDelegate {
- var window: UIWindow?
+ var window: WKRWindow?
func configureConstants() {
WKRKitConstants.updateConstants()
@@ -24,20 +24,6 @@ internal class WKRAppDelegate: UIResponder, UIApplicationDelegate {
SKStoreReviewController.shouldPromptForRating = false
}
- func configureAppearance() {
- UINavigationBar.appearance().tintColor = UIColor.wkrTextColor
-
- UINavigationBar.appearance().titleTextAttributes = [
- .foregroundColor: UIColor.wkrTextColor,
- .font: UIFont.systemFont(ofSize: 18, weight: .semibold)
- ]
- window?.backgroundColor = UIColor.wkrBackgroundColor
-
- if WKRUIStyle.isDark {
- UILabel.appearance(whenContainedInInstancesOf: [UITableViewHeaderFooterView.self]).textColor = UIColor.white
- }
- }
-
func cleanTempDirectory() {
let maxDayAge = 14.0
let maxTimeInterval = maxDayAge * 60 * 60
diff --git a/WikiRaces/Shared/Other/WKRWindow.swift b/WikiRaces/Shared/Other/WKRWindow.swift
new file mode 100644
index 0000000..2ff6436
--- /dev/null
+++ b/WikiRaces/Shared/Other/WKRWindow.swift
@@ -0,0 +1,17 @@
+//
+// WKRWindow.swift
+// WikiRaces
+//
+// Created by Andrew Finke on 9/25/19.
+// Copyright © 2019 Andrew Finke. All rights reserved.
+//
+
+import UIKit
+import WKRUIKit
+
+class WKRWindow: UIWindow {
+ override func layoutSubviews() {
+ super.layoutSubviews()
+ backgroundColor = .wkrBackgroundColor(for: traitCollection)
+ }
+}
diff --git a/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController+KB.swift b/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController+KB.swift
index eabcd58..6762942 100644
--- a/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController+KB.swift
+++ b/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController+KB.swift
@@ -73,14 +73,15 @@ extension GameViewController {
@objc
private func keyboardAttemptToggleSection(_ keyCommand: UIKeyCommand) {
- guard let input = keyCommand.input,
+ guard let webView = webView,
+ let input = keyCommand.input,
let index = Int(input),
gameState == .race else {
return
}
let script = "document.getElementsByClassName('section-heading')[\(index - 1)].click()"
- webView?.evaluateJavaScript(script, completionHandler: nil)
+ webView.evaluateJavaScript(script, completionHandler: nil)
}
}
diff --git a/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController+Manager.swift b/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController+Manager.swift
index d32d073..bb08612 100644
--- a/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController+Manager.swift
+++ b/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController+Manager.swift
@@ -8,10 +8,11 @@
import Foundation
import WKRKit
+import WKRUIKit
extension GameViewController {
- // MARK: - WKRGameManager
+ // MARK: - WKRGameManager -
func setupGameManager() {
gameManager = WKRGameManager(networkConfig: networkConfig,
@@ -168,7 +169,7 @@ extension GameViewController {
#endif
}
- // MARK: - Controllers
+ // MARK: - Controllers -
func resetActiveControllers() {
alertController = nil
@@ -198,7 +199,7 @@ extension GameViewController {
}
}
- // MARK: - Transitions
+ // MARK: - Transitions -
private func transition(to state: WKRGameState, completion: @escaping () -> Void) {
guard state != gameState else {
@@ -259,9 +260,13 @@ extension GameViewController {
self.votingViewController = controller
- let navController = UINavigationController(rootViewController: controller)
+ let navController = WKRUINavigationController(rootViewController: controller)
navController.modalTransitionStyle = .crossDissolve
navController.modalPresentationStyle = .overCurrentContext
+ if #available(iOS 13.0, *) {
+ navController.isModalInPresentation = true
+ }
+
present(navController, animated: true) { [weak self] in
self?.connectingLabel.alpha = 0.0
self?.activityIndicatorView.alpha = 0.0
@@ -317,9 +322,13 @@ extension GameViewController {
self.resultsViewController = controller
- let navController = UINavigationController(rootViewController: controller)
+ let navController = WKRUINavigationController(rootViewController: controller)
navController.modalTransitionStyle = .crossDissolve
navController.modalPresentationStyle = .overCurrentContext
+ if #available(iOS 13.0, *) {
+ navController.isModalInPresentation = true
+ }
+
present(navController, animated: true) { [weak self] in
self?.connectingLabel.alpha = 0.0
self?.activityIndicatorView.alpha = 0.0
@@ -350,7 +359,7 @@ extension GameViewController {
}
}
- // MARK: - Log Final Votes
+ // MARK: - Log Final Votes -
private func logFinalVotes() {
guard networkConfig.isHost, let votingInfo = gameManager.voteInfo else { return }
diff --git a/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController+UI.swift b/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController+UI.swift
index fad49c3..aaadb87 100644
--- a/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController+UI.swift
+++ b/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController+UI.swift
@@ -13,9 +13,11 @@ extension GameViewController {
// MARK: - Interface
+ #if !targetEnvironment(macCatalyst)
override var prefersHomeIndicatorAutoHidden: Bool {
return true
}
+ #endif
func setupInterface() {
guard let navigationController = navigationController,
@@ -23,8 +25,6 @@ extension GameViewController {
fatalError("No navigation controller view")
}
- view.backgroundColor = UIColor.wkrBackgroundColor
-
helpBarButtonItem = UIBarButtonItem(image: UIImage(named: "HelpFlag")!,
style: .plain,
target: self,
@@ -44,7 +44,6 @@ extension GameViewController {
} else {
navigationController.setNavigationBarHidden(true, animated: false)
}
- navigationController.navigationBar.barStyle = UIBarStyle.wkrStyle
navigationView.addSubview(navigationBarBottomLine)
setupElements()
@@ -71,14 +70,12 @@ extension GameViewController {
private func setupElements() {
navigationBarBottomLine.alpha = 0
- navigationBarBottomLine.backgroundColor = UIColor.wkrTextColor
navigationBarBottomLine.translatesAutoresizingMaskIntoConstraints = false
connectingLabel.translatesAutoresizingMaskIntoConstraints = false
connectingLabel.alpha = 0.0
connectingLabel.text = "CONNECTING"
connectingLabel.textAlignment = .center
- connectingLabel.textColor = .wkrTextColor
connectingLabel.font = UIFont.systemFont(ofSize: 24, weight: .medium)
view.addSubview(connectingLabel)
@@ -112,7 +109,6 @@ extension GameViewController {
view.addSubview(webView)
view.bringSubviewToFront(progressView)
webView.progressView = progressView
- webView.backgroundColor = UIColor.wkrBackgroundColor
let constraints: [NSLayoutConstraint] = [
webView.topAnchor.constraint(equalTo: view.topAnchor),
diff --git a/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController.swift b/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController.swift
index d075523..7d48549 100644
--- a/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController.swift
+++ b/WikiRaces/Shared/Race View Controllers/GameViewController/GameViewController.swift
@@ -80,12 +80,14 @@ internal class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
-
- if !UserDefaults.standard.bool(forKey: "FASTLANE_SNAPSHOT") {
+ if UserDefaults.standard.bool(forKey: "FASTLANE_SNAPSHOT") {
+ setupInterface()
+ let url = URL(string: "https://en.m.wikipedia.org/wiki/Walt_Disney_World_Monorail_System")!
+ prepareForScreenshots(for: url)
+ } else {
setupGameManager()
+ setupInterface()
}
-
- setupInterface()
}
override func viewDidAppear(_ animated: Bool) {
@@ -117,6 +119,15 @@ internal class GameViewController: UIViewController {
}
}
+ override func viewWillLayoutSubviews() {
+ super.viewWillLayoutSubviews()
+ let textColor: UIColor = .wkrTextColor(for: traitCollection)
+ navigationBarBottomLine.backgroundColor = textColor
+ connectingLabel.textColor = textColor
+ view.backgroundColor = .wkrBackgroundColor(for: traitCollection)
+ activityIndicatorView.color = .wkrActivityIndicatorColor(for: traitCollection)
+ }
+
private func initalConfiguration() {
let logEvents: [WKRLogEvent]
if networkConfig.isHost {
@@ -154,6 +165,10 @@ internal class GameViewController: UIViewController {
}
}
+ deinit {
+ gameManager.alertView.removeFromSuperview()
+ }
+
// MARK: - User Actions
@objc
@@ -184,13 +199,13 @@ internal class GameViewController: UIViewController {
}
self.activeViewController = controller
- let navController = UINavigationController(rootViewController: controller)
+ let navController = WKRUINavigationController(rootViewController: controller)
navController.modalPresentationStyle = .formSheet
present(navController, animated: true, completion: nil)
PlayerAnonymousMetrics.log(event: .userAction("flagButtonPressed:help"))
PlayerAnonymousMetrics.log(event: .usedHelp,
- attributes: ["Page": self.finalPage?.title as Any])
+ attributes: ["Page": self.finalPage?.title as Any])
if let raceType = statRaceType {
let stat: PlayerDatabaseStat
switch raceType {
diff --git a/WikiRaces/Shared/Race View Controllers/HistoryViewController/HistoryTableViewCell.swift b/WikiRaces/Shared/Race View Controllers/HistoryViewController/HistoryTableViewCell.swift
index a673b5d..390c9c8 100644
--- a/WikiRaces/Shared/Race View Controllers/HistoryViewController/HistoryTableViewCell.swift
+++ b/WikiRaces/Shared/Race View Controllers/HistoryViewController/HistoryTableViewCell.swift
@@ -10,14 +10,14 @@ import UIKit
internal class HistoryTableViewCell: UITableViewCell {
- // MARK: - Properties
+ // MARK: - Properties -
let pageLabel = UILabel()
let detailLabel = UILabel()
private let linkHereLabel = UILabel()
private let activityIndicatorView = UIActivityIndicatorView(style: .gray)
- private var linkLabelTopConstraint: NSLayoutConstraint!
+ private var linkLabelTopConstraint: NSLayoutConstraint?
var isShowingActivityIndicatorView: Bool = false {
didSet {
@@ -33,22 +33,17 @@ internal class HistoryTableViewCell: UITableViewCell {
var isLinkHere: Bool = true {
didSet {
linkHereLabel.text = isLinkHere ? "Link Here" : nil
- linkLabelTopConstraint.constant = isLinkHere ? 5 : 0
+ linkLabelTopConstraint?.constant = isLinkHere ? 5 : 0
}
-
}
static let reuseIdentifier = "reuseIdentifier"
- // MARK: - Initialization
+ // MARK: - Initialization -
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
- tintColor = UIColor.wkrTextColor
- backgroundColor = UIColor.wkrBackgroundColor
-
- pageLabel.textColor = UIColor.wkrTextColor
pageLabel.textAlignment = .left
pageLabel.font = UIFont.systemFont(ofSize: 17, weight: .regular)
pageLabel.numberOfLines = 0
@@ -56,7 +51,7 @@ internal class HistoryTableViewCell: UITableViewCell {
addSubview(pageLabel)
linkHereLabel.text = "Link Here"
- linkHereLabel.textColor = UIColor.lightGray
+ linkHereLabel.textColor = .lightGray
linkHereLabel.textAlignment = .left
linkHereLabel.font = UIFont.systemFont(ofSize: 16, weight: .medium)
linkHereLabel.numberOfLines = 1
@@ -64,26 +59,35 @@ internal class HistoryTableViewCell: UITableViewCell {
addSubview(linkHereLabel)
detailLabel.textAlignment = .right
- detailLabel.textColor = UIColor.wkrTextColor
detailLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
detailLabel.translatesAutoresizingMaskIntoConstraints = false
addSubview(detailLabel)
- activityIndicatorView.color = UIColor.wkrActivityIndicatorColor
activityIndicatorView.hidesWhenStopped = true
activityIndicatorView.stopAnimating()
activityIndicatorView.setContentCompressionResistancePriority(.required, for: .horizontal)
activityIndicatorView.translatesAutoresizingMaskIntoConstraints = false
addSubview(activityIndicatorView)
- setupConstraints()
+ setupConstraints()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
- // MARK: - Constraints
+ // MARK: - View Life Cycle -
+
+ public override func layoutSubviews() {
+ super.layoutSubviews()
+ let textColor = UIColor.wkrTextColor(for: traitCollection)
+ tintColor = textColor
+ pageLabel.textColor = textColor
+ detailLabel.textColor = textColor
+ activityIndicatorView.color = .wkrActivityIndicatorColor(for: traitCollection)
+ }
+
+ // MARK: - Constraints -
private func setupConstraints() {
let leftMarginConstraint = NSLayoutConstraint(item: pageLabel,
@@ -102,8 +106,9 @@ internal class HistoryTableViewCell: UITableViewCell {
multiplier: 1.0,
constant: 0.0)
- linkLabelTopConstraint = linkHereLabel.topAnchor.constraint(equalTo: pageLabel.bottomAnchor,
- constant: 5)
+ let linkLabelTopConstraint = linkHereLabel.topAnchor.constraint(equalTo: pageLabel.bottomAnchor,
+ constant: 5)
+ self.linkLabelTopConstraint = linkLabelTopConstraint
let constraints = [
leftMarginConstraint,
@@ -112,7 +117,7 @@ internal class HistoryTableViewCell: UITableViewCell {
pageLabel.rightAnchor.constraint(lessThanOrEqualTo: detailLabel.leftAnchor, constant: -15),
pageLabel.rightAnchor.constraint(lessThanOrEqualTo: activityIndicatorView.leftAnchor, constant: -15),
- linkLabelTopConstraint!,
+ linkLabelTopConstraint,
linkHereLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10),
linkHereLabel.leftAnchor.constraint(equalTo: pageLabel.leftAnchor),
linkHereLabel.rightAnchor.constraint(equalTo: pageLabel.rightAnchor),
diff --git a/WikiRaces/Shared/Race View Controllers/HistoryViewController/HistoryTableViewStatsCell.swift b/WikiRaces/Shared/Race View Controllers/HistoryViewController/HistoryTableViewStatsCell.swift
index 0770078..40893d1 100644
--- a/WikiRaces/Shared/Race View Controllers/HistoryViewController/HistoryTableViewStatsCell.swift
+++ b/WikiRaces/Shared/Race View Controllers/HistoryViewController/HistoryTableViewStatsCell.swift
@@ -10,25 +10,38 @@ import UIKit
internal class HistoryTableViewStatsCell: UITableViewCell {
- // MARK: - Properties
+ // MARK: - Properties -
+
+ static let reuseIdentifier = "statsReuseIdentifier"
var stat: (key: String, value: String)? {
didSet {
- textLabel?.text = stat?.key
- detailTextLabel?.text = stat?.value
+ statLabel.text = stat?.key
+ detailLabel.text = stat?.value
}
}
- static let reuseIdentifier = "statsReuseIdentifier"
+ let statLabel = UILabel()
+ let detailLabel = UILabel()
- // MARK: - Initialization
+ // MARK: - Initialization -
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
- super.init(style: .value1, reuseIdentifier: reuseIdentifier)
+ super.init(style: style, reuseIdentifier: reuseIdentifier)
+
+ statLabel.textAlignment = .left
+ statLabel.font = UIFont.systemFont(ofSize: 17, weight: .regular)
+ statLabel.numberOfLines = 0
+ statLabel.translatesAutoresizingMaskIntoConstraints = false
+ addSubview(statLabel)
- textLabel?.textColor = .wkrTextColor
- detailTextLabel?.textColor = .wkrTextColor
- detailTextLabel?.font = UIFont.systemFont(ofSize: 17, weight: .medium)
+ detailLabel.font = UIFont.systemFont(ofSize: 17, weight: .medium)
+ detailLabel.textAlignment = .right
+ detailLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
+ detailLabel.translatesAutoresizingMaskIntoConstraints = false
+ addSubview(detailLabel)
+
+ setupConstraints()
isUserInteractionEnabled = false
}
@@ -36,4 +49,45 @@ internal class HistoryTableViewStatsCell: UITableViewCell {
fatalError("init(coder:) has not been implemented")
}
+ // MARK: - View Life Cycle -
+
+ public override func layoutSubviews() {
+ super.layoutSubviews()
+ let textColor = UIColor.wkrTextColor(for: traitCollection)
+ tintColor = textColor
+ statLabel.textColor = textColor
+ detailLabel.textColor = textColor
+ }
+
+ // MARK: - Constraints -
+
+ private func setupConstraints() {
+ let leftMarginConstraint = NSLayoutConstraint(item: statLabel,
+ attribute: .left,
+ relatedBy: .equal,
+ toItem: self,
+ attribute: .leftMargin,
+ multiplier: 1.0,
+ constant: 0.0)
+
+ let rightMarginConstraint = NSLayoutConstraint(item: detailLabel,
+ attribute: .right,
+ relatedBy: .equal,
+ toItem: self,
+ attribute: .rightMargin,
+ multiplier: 1.0,
+ constant: 0.0)
+
+ let constraints = [
+ leftMarginConstraint,
+ statLabel.topAnchor.constraint(equalTo: topAnchor, constant: 10),
+ statLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 15),
+ statLabel.rightAnchor.constraint(lessThanOrEqualTo: detailLabel.leftAnchor, constant: -15),
+
+ rightMarginConstraint,
+ detailLabel.centerYAnchor.constraint(equalTo: centerYAnchor)
+ ]
+ NSLayoutConstraint.activate(constraints)
+ }
+
}
diff --git a/WikiRaces/Shared/Race View Controllers/HistoryViewController/HistoryViewController+KB.swift b/WikiRaces/Shared/Race View Controllers/HistoryViewController/HistoryViewController+KB.swift
index 096913f..4d6c6ca 100644
--- a/WikiRaces/Shared/Race View Controllers/HistoryViewController/HistoryViewController+KB.swift
+++ b/WikiRaces/Shared/Race View Controllers/HistoryViewController/HistoryViewController+KB.swift
@@ -10,7 +10,7 @@ import UIKit
extension HistoryViewController {
- // MARK: - Keyboard Support
+ // MARK: - Keyboard Support -
override var keyCommands: [UIKeyCommand]? {
return [
diff --git a/WikiRaces/Shared/Race View Controllers/HistoryViewController/HistoryViewController.swift b/WikiRaces/Shared/Race View Controllers/HistoryViewController/HistoryViewController.swift
index 368a499..35ba58f 100644
--- a/WikiRaces/Shared/Race View Controllers/HistoryViewController/HistoryViewController.swift
+++ b/WikiRaces/Shared/Race View Controllers/HistoryViewController/HistoryViewController.swift
@@ -14,7 +14,7 @@ import SafariServices
internal class HistoryViewController: UITableViewController, SFSafariViewControllerDelegate {
- // MARK: - Properties
+ // MARK: - Properties -
private var isUserScrolling = false
private var isTableViewAnimating = false
@@ -24,13 +24,15 @@ internal class HistoryViewController: UITableViewController, SFSafariViewControl
private var entries = [WKRHistoryEntry]()
private var stats: WKRPlayerRaceStats?
+ private var safariController: SFSafariViewController?
+
var player: WKRPlayer? {
didSet {
updateEntries(oldPlayer: oldValue)
}
}
- // MARK: - View Life Cycle
+ // MARK: - View Life Cycle -
override func viewDidLoad() {
super.viewDidLoad()
@@ -39,8 +41,6 @@ internal class HistoryViewController: UITableViewController, SFSafariViewControl
frame.size.height = .leastNormalMagnitude
tableView.tableHeaderView = UIView(frame: frame)
- navigationController?.navigationBar.barStyle = .wkrStyle
-
tableView.estimatedRowHeight = 150
tableView.rowHeight = UITableView.automaticDimension
tableView.register(HistoryTableViewCell.self,
@@ -53,7 +53,12 @@ internal class HistoryViewController: UITableViewController, SFSafariViewControl
action: #selector(doneButtonPressed))
}
- // MARK: - Logic
+ override func viewWillLayoutSubviews() {
+ super.viewWillLayoutSubviews()
+ safariController?.preferredControlTintColor = .wkrTextColor(for: traitCollection)
+ }
+
+ // MARK: - Logic -
// Update the table, with the goal of only updating the changed entries
// 1. Make sure the player is the same as the currently displayed one (else update the whole table)
@@ -165,14 +170,14 @@ internal class HistoryViewController: UITableViewController, SFSafariViewControl
})
}
- // MARK: - Actions
+ // MARK: - Actions -
@IBAction func doneButtonPressed() {
PlayerAnonymousMetrics.log(event: .userAction(#function))
presentingViewController?.dismiss(animated: true, completion: nil)
}
- // MARK: - UIScrollViewDelegate
+ // MARK: - UIScrollViewDelegate -
override func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
isUserScrolling = true
@@ -185,7 +190,7 @@ internal class HistoryViewController: UITableViewController, SFSafariViewControl
}
}
- // MARK: - Table view data source
+ // MARK: - Table view data source -
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
@@ -246,20 +251,23 @@ internal class HistoryViewController: UITableViewController, SFSafariViewControl
let controller = SFSafariViewController(url: entry.page.url)
controller.delegate = self
- controller.preferredControlTintColor = UIColor.wkrTextColor
+
+ controller.preferredControlTintColor = .wkrTextColor(for: traitCollection)
if UIDevice.current.userInterfaceIdiom == .pad {
controller.modalPresentationStyle = .overFullScreen
}
present(controller, animated: true, completion: nil)
+ safariController = controller
PlayerAnonymousMetrics.log(event: .openedHistorySF)
}
- // MARK: - SFSafariViewControllerDelegate
+ // MARK: - SFSafariViewControllerDelegate -
func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
guard let indexPath = tableView.indexPathForSelectedRow else { return }
tableView.deselectRow(at: indexPath, animated: true)
+ safariController = nil
}
}
diff --git a/WikiRaces/Shared/Race View Controllers/Other/CenteredTableViewController.swift b/WikiRaces/Shared/Race View Controllers/Other/CenteredTableViewController.swift
index 5ffc8d1..c9acd1d 100644
--- a/WikiRaces/Shared/Race View Controllers/Other/CenteredTableViewController.swift
+++ b/WikiRaces/Shared/Race View Controllers/Other/CenteredTableViewController.swift
@@ -60,11 +60,17 @@ internal class CenteredTableViewController: UIViewController {
isInterfaceLoaded = true
}
+ override func viewWillLayoutSubviews() {
+ super.viewWillLayoutSubviews()
+ guideLabel.textColor = .wkrSubtitleTextColor(for: traitCollection)
+ descriptionLabel.textColor = .wkrTextColor(for: traitCollection)
+ }
+
// MARK: - Interface
//swiftlint:disable:next function_body_length
private func setupInterface() {
- let visualEffectView = UIVisualEffectView(effect: UIBlurEffect.wkrBlurEffect)
+ let visualEffectView = UIVisualEffectView(effect: UIBlurEffect.wkrLightBlurEffect)
tableView.estimatedRowHeight = 0
tableView.isUserInteractionEnabled = false
@@ -74,14 +80,12 @@ internal class CenteredTableViewController: UIViewController {
tableView.allowsSelection = true
guideLabel.textAlignment = .center
- guideLabel.textColor = UIColor.wkrLightTextColor
guideLabel.font = UIFont.systemFont(ofSize: 18.0, weight: .medium)
guideLabel.adjustsFontSizeToFitWidth = true
guideLabel.translatesAutoresizingMaskIntoConstraints = false
visualEffectView.contentView.addSubview(guideLabel)
descriptionLabel.textAlignment = .center
- descriptionLabel.textColor = UIColor.wkrTextColor
descriptionLabel.font = UIFont(monospaceSize: 20, weight: .medium)
descriptionLabel.adjustsFontSizeToFitWidth = true
descriptionLabel.translatesAutoresizingMaskIntoConstraints = false
@@ -101,7 +105,6 @@ internal class CenteredTableViewController: UIViewController {
navigationController?.navigationBar.shadowImage = UIImage()
navigationController?.navigationBar.isTranslucent = true
navigationController?.view.backgroundColor = .clear
- navigationController?.navigationBar.barStyle = UIBarStyle.wkrStyle
descriptionLabelBottomConstraint = descriptionLabel.bottomAnchor.constraint(equalTo: overlayView.topAnchor)
diff --git a/WikiRaces/Shared/Race View Controllers/Other/HelpViewController.swift b/WikiRaces/Shared/Race View Controllers/Other/HelpViewController.swift
index 5c2c224..d0bd082 100644
--- a/WikiRaces/Shared/Race View Controllers/Other/HelpViewController.swift
+++ b/WikiRaces/Shared/Race View Controllers/Other/HelpViewController.swift
@@ -12,23 +12,20 @@ import WKRUIKit
internal class HelpViewController: UIViewController, WKNavigationDelegate {
- // MARK: - Properties
+ // MARK: - Properties -
var url: URL?
var linkTapped: (() -> Void)?
- let webView = WKRUIWebView()
- let progressView = WKRUIProgressView()
+ private let webView = WKRUIWebView()
+ private let progressView = WKRUIProgressView()
- // MARK: - View Life Cycle
+ // MARK: - View Life Cycle -
override func viewDidLoad() {
super.viewDidLoad()
title = "HELP"
- view.backgroundColor = UIColor.wkrBackgroundColor
- navigationController?.navigationBar.barStyle = UIBarStyle.wkrStyle
- navigationController?.view.backgroundColor = UIColor.wkrBackgroundColor
webView.text = ""
webView.navigationDelegate = self
@@ -64,14 +61,19 @@ internal class HelpViewController: UIViewController, WKNavigationDelegate {
action: #selector(doneButtonPressed))
}
- // MARK: - Actions
+ override func viewWillLayoutSubviews() {
+ super.viewWillLayoutSubviews()
+ navigationController?.view.backgroundColor = .wkrBackgroundColor(for: traitCollection)
+ }
+
+ // MARK: - Actions -
@IBAction func doneButtonPressed() {
PlayerAnonymousMetrics.log(event: .userAction(#function))
presentingViewController?.dismiss(animated: true, completion: nil)
}
- // MARK: - WKNavigationDelegate
+ // MARK: - WKNavigationDelegate -
func webView(_ webView: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction,
diff --git a/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultRenderer+Creation.swift b/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultRenderer+Creation.swift
index b259c8a..a1bb0f1 100644
--- a/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultRenderer+Creation.swift
+++ b/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultRenderer+Creation.swift
@@ -12,7 +12,7 @@ import WKRKit
//swiftlint:disable function_body_length cyclomatic_complexity
extension ResultRenderer {
- // MARK: - Section Creation
+ // MARK: - Section Creation -
func createHeaderView(title: String) -> UIView {
let headerView = UIView()
@@ -122,6 +122,7 @@ extension ResultRenderer {
let nameLabel = UILabel()
nameLabel.translatesAutoresizingMaskIntoConstraints = false
nameLabel.numberOfLines = 0
+ nameLabel.textColor = .black
var placeString = (index + 1).description + "th"
if index == 0 {
@@ -227,6 +228,7 @@ extension ResultRenderer {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
+ label.textColor = .black
let num = index + 1
let indexString = num.description + ". "
diff --git a/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultRenderer.swift b/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultRenderer.swift
index 28685da..bd65695 100644
--- a/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultRenderer.swift
+++ b/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultRenderer.swift
@@ -12,7 +12,7 @@ import WKRKit
//swiftlint:disable function_body_length
class ResultRenderer {
- // MARK: - Types
+ // MARK: - Types -
private class RenderView: UIView {
var onLayout: (() -> Void)?
@@ -22,12 +22,12 @@ class ResultRenderer {
}
}
- // MARK: - Properties
+ // MARK: - Properties -
let tintColor = #colorLiteral(red: 54.0/255.0, green: 54.0/255.0, blue: 54.0/255.0, alpha: 1.0)
private var isRendering = false
- // MARK: - Rendering
+ // MARK: - Rendering -
func render(with results: WKRResultsInfo,
for localPlayer: WKRPlayer,
diff --git a/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultsTableViewCell.swift b/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultsTableViewCell.swift
index a1812cb..fe0e34b 100644
--- a/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultsTableViewCell.swift
+++ b/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultsTableViewCell.swift
@@ -11,7 +11,7 @@ import WKRKit
internal class ResultsTableViewCell: UITableViewCell {
- // MARK: - Properties
+ // MARK: - Properties -
private let playerLabel = UILabel()
private let detailLabel = UILabel()
@@ -32,7 +32,11 @@ internal class ResultsTableViewCell: UITableViewCell {
didSet {
guard isShowingCheckmark != oldValue else { return }
if isShowingCheckmark {
- rightMarginConstraint?.constant = -20
+ if #available(iOS 13.0, *) {
+ rightMarginConstraint?.constant = -30
+ } else {
+ rightMarginConstraint?.constant = -20
+ }
} else {
rightMarginConstraint?.constant = 0
}
@@ -52,37 +56,34 @@ internal class ResultsTableViewCell: UITableViewCell {
}
private let activityIndicatorView = UIActivityIndicatorView(style: .gray)
+ private var isPlayerCreator = false
- // MARK: - Initialization
+ // MARK: - Initialization -
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
- tintColor = UIColor.wkrTextColor
selectionStyle = .none
- backgroundColor = UIColor.clear
+ backgroundColor = .clear
- playerLabel.textColor = UIColor.wkrTextColor
playerLabel.textAlignment = .left
playerLabel.font = UIFont.systemFont(ofSize: 18, weight: .medium)
playerLabel.numberOfLines = 0
playerLabel.translatesAutoresizingMaskIntoConstraints = false
addSubview(playerLabel)
- subtitleLabel.textColor = UIColor.wkrTextColor
subtitleLabel.textAlignment = .left
subtitleLabel.numberOfLines = 1
subtitleLabel.translatesAutoresizingMaskIntoConstraints = false
addSubview(subtitleLabel)
detailLabel.textAlignment = .right
- detailLabel.textColor = UIColor.lightGray
+ detailLabel.textColor = .lightGray
detailLabel.font = UIFont.systemFont(ofSize: 20, weight: .medium)
detailLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
detailLabel.translatesAutoresizingMaskIntoConstraints = false
addSubview(detailLabel)
- activityIndicatorView.color = UIColor.wkrActivityIndicatorColor
activityIndicatorView.hidesWhenStopped = true
activityIndicatorView.stopAnimating()
activityIndicatorView.setContentCompressionResistancePriority(.required, for: .horizontal)
@@ -96,7 +97,20 @@ internal class ResultsTableViewCell: UITableViewCell {
super.init(coder: aDecoder)
}
- // MARK: - Constraints
+ // MARK: - View Life Cycle -
+
+ public override func layoutSubviews() {
+ super.layoutSubviews()
+ let textColor = UIColor.wkrTextColor(for: traitCollection)
+ tintColor = textColor
+ if !isPlayerCreator {
+ playerLabel.textColor = textColor
+ }
+ subtitleLabel.textColor = textColor
+ activityIndicatorView.color = .wkrActivityIndicatorColor(for: traitCollection)
+ }
+
+ // MARK: - Constraints -
private func setupConstraints() {
let leftMarginConstraint = NSLayoutConstraint(item: playerLabel,
@@ -145,7 +159,7 @@ internal class ResultsTableViewCell: UITableViewCell {
NSLayoutConstraint.activate(constraints)
}
- // MARK: - Updating
+ // MARK: - Updating -
private func update(playerName: NSAttributedString,
detail: String,
@@ -199,7 +213,7 @@ internal class ResultsTableViewCell: UITableViewCell {
let range = NSRange(location: pageTitle.count, length: detail.count)
let attributes: [NSAttributedString.Key: Any] = [
.foregroundColor: UIColor.lightGray,
- .font: UIFont.systemFont(ofSize: 15)
+ .font: UIFont.systemFont(ofSize: 13, weight: .semibold)
]
pageTitleAttributedString.addAttributes(attributes, range: range)
}
@@ -244,23 +258,28 @@ internal class ResultsTableViewCell: UITableViewCell {
subtitleString += sessionResults.isTied ? " (Tied)" : ""
update(playerName: NSAttributedString(string: sessionResults.profile.name),
- detail: detailString,
- subtitle: NSAttributedString(string: subtitleString),
- animated: false)
+ detail: detailString,
+ subtitle: NSAttributedString(string: subtitleString),
+ animated: false)
}
- // MARK: - Other
+ // MARK: - Other -
func playerNameAttributedString(for player: WKRPlayer) -> NSAttributedString {
if let isCreator = player.isCreator, isCreator {
+ self.isPlayerCreator = true
let name = player.name
let nameAttributedString = NSMutableAttributedString(string: name, attributes: nil)
let range = NSRange(location: 0, length: name.count)
+
+ let font = UIFont.systemRoundedFont(ofSize: 20, weight: .semibold) ??
+ UIFont.systemFont(ofSize: 18, weight: .medium)
let attributes: [NSAttributedString.Key: Any] = [
.foregroundColor: UIColor(displayP3Red: 69.0/255.0,
green: 145.0/255.0,
blue: 208.0/255.0,
- alpha: 1.0)
+ alpha: 1.0),
+ .font: font
]
nameAttributedString.addAttributes(attributes, range: range)
return nameAttributedString
diff --git a/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultsViewController+Actions.swift b/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultsViewController+Actions.swift
index 2e12aaf..946afe4 100644
--- a/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultsViewController+Actions.swift
+++ b/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultsViewController+Actions.swift
@@ -34,12 +34,28 @@ extension ResultsViewController {
PlayerAnonymousMetrics.log(event: .userAction(#function))
guard let image = resultImage else { return }
+ let hackTitle = "Hack"
let controller = UIActivityViewController(activityItems: [
image,
"#WikiRaces3"
], applicationActivities: nil)
+ controller.completionWithItemsHandler = { [weak self] activityType, completed, _, _ in
+ if !(completed && activityType == UIActivity.ActivityType.saveToCameraRoll),
+ let hack = self?.presentedViewController,
+ hack.title == hackTitle {
+ self?.dismiss(animated: false, completion: nil)
+ }
+ }
controller.popoverPresentationController?.barButtonItem = sender
- present(controller, animated: true, completion: nil)
+
+ // seriously, iOS 13 broke activity sheet save to photos??
+ let hack = UIViewController()
+ hack.title = hackTitle
+ hack.view.alpha = 0.0
+ hack.modalPresentationStyle = .overCurrentContext
+ present(hack, animated: false, completion: {
+ hack.present(controller, animated: true, completion: nil)
+ })
PlayerAnonymousMetrics.log(event: .openedShare)
}
}
diff --git a/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultsViewController+KB.swift b/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultsViewController+KB.swift
index 00c1246..0ab8e3a 100644
--- a/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultsViewController+KB.swift
+++ b/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultsViewController+KB.swift
@@ -10,7 +10,7 @@ import UIKit
extension ResultsViewController {
- // MARK: - Keyboard Support
+ // MARK: - Keyboard Support -
override var keyCommands: [UIKeyCommand]? {
var commands = [UIKeyCommand]()
diff --git a/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultsViewController+TableView.swift b/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultsViewController+TableView.swift
index bc374e6..387d5cb 100644
--- a/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultsViewController+TableView.swift
+++ b/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultsViewController+TableView.swift
@@ -8,6 +8,7 @@
import UIKit
import WKRKit
+import WKRUIKit
extension ResultsViewController: UITableViewDataSource, UITableViewDelegate {
@@ -56,7 +57,7 @@ extension ResultsViewController: UITableViewDataSource, UITableViewDelegate {
historyViewController = controller
controller.player = resultsInfo.raceRankingsPlayer(at: indexPath.row)
- let navController = UINavigationController(rootViewController: controller)
+ let navController = WKRUINavigationController(rootViewController: controller)
navController.modalPresentationStyle = .formSheet
present(navController, animated: true, completion: nil)
diff --git a/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultsViewController.swift b/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultsViewController.swift
index 3f364d1..26424e3 100644
--- a/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultsViewController.swift
+++ b/WikiRaces/Shared/Race View Controllers/ResultsViewController/ResultsViewController.swift
@@ -12,14 +12,14 @@ import WKRUIKit
internal class ResultsViewController: CenteredTableViewController {
- // MARK: - Types
+ // MARK: - Types -
enum ListenerUpdate {
case readyButtonPressed
case quit
}
- // MARK: - Properties
+ // MARK: - Properties -
var listenerUpdate: ((ListenerUpdate) -> Void)?
var historyViewController: HistoryViewController?
@@ -40,7 +40,7 @@ internal class ResultsViewController: CenteredTableViewController {
}
}
- // MARK: - Game States
+ // MARK: - Game States -
var localPlayer: WKRPlayer?
@@ -83,7 +83,7 @@ internal class ResultsViewController: CenteredTableViewController {
}
}
- // MARK: - View Life Cycle
+ // MARK: - View Life Cycle -
override func viewDidLoad() {
super.viewDidLoad()
@@ -124,11 +124,7 @@ internal class ResultsViewController: CenteredTableViewController {
action: #selector(doneButtonPressed))
}
- override var preferredStatusBarStyle: UIStatusBarStyle {
- return UIStatusBarStyle.wkrStatusBarStyle
- }
-
- // MARK: - Game Updates
+ // MARK: - Game Updates -
private func updatedState(oldState: WKRGameState) {
if state == .results || state == .hostResults {
@@ -138,7 +134,11 @@ internal class ResultsViewController: CenteredTableViewController {
} else {
tableView.isUserInteractionEnabled = false
- if presentedViewController != nil {
+ if let hack = presentedViewController, hack.title == "Hack" {
+ hack.dismiss(animated: true) { [weak self] in
+ self?.dismiss(animated: false, completion: nil)
+ }
+ } else if presentedViewController != nil {
dismiss(animated: true, completion: nil)
}
@@ -217,7 +217,7 @@ internal class ResultsViewController: CenteredTableViewController {
}
}
- // MARK: - Helpers
+ // MARK: - Helpers -
private func updatedResultsImage() {
guard let image = resultImage, UserDefaults.standard.bool(forKey: "force_save_result_image") else { return }
diff --git a/WikiRaces/Shared/Race View Controllers/VotingViewController/VotingTableViewCell.swift b/WikiRaces/Shared/Race View Controllers/VotingViewController/VotingTableViewCell.swift
index 85c4ad1..a7f53ee 100644
--- a/WikiRaces/Shared/Race View Controllers/VotingViewController/VotingTableViewCell.swift
+++ b/WikiRaces/Shared/Race View Controllers/VotingViewController/VotingTableViewCell.swift
@@ -12,23 +12,22 @@ import WKRKit
internal class VotingTableViewCell: UITableViewCell {
- // MARK: - Properties
+ // MARK: - Properties -
private let titleLabel = UILabel()
private let countLabel = UILabel()
private let stackView = UIStackView()
- // MARK: - Property Observers
+ // MARK: - Property Observers -
override var isSelected: Bool {
didSet {
if isSelected {
- countLabel.textColor = UIColor.wkrVoteCountSelectedTextColor
countLabel.font = UIFont.systemFont(ofSize: 22, weight: .medium)
} else {
- countLabel.textColor = UIColor.wkrVoteCountTextColor
countLabel.font = UIFont.systemFont(ofSize: 18, weight: .medium)
}
+ setNeedsLayout()
}
}
@@ -44,7 +43,7 @@ internal class VotingTableViewCell: UITableViewCell {
}
}
- // MARK: - Initialization
+ // MARK: - Initialization -
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
@@ -56,14 +55,12 @@ internal class VotingTableViewCell: UITableViewCell {
stackView.distribution = .fillProportionally
stackView.alignment = .center
- titleLabel.textColor = UIColor.wkrTextColor
titleLabel.text = ""
titleLabel.textAlignment = .left
titleLabel.font = UIFont.systemFont(ofSize: 18, weight: .medium)
countLabel.text = "0"
countLabel.textAlignment = .right
- countLabel.textColor = UIColor.wkrVoteCountTextColor
stackView.addArrangedSubview(titleLabel)
stackView.addArrangedSubview(countLabel)
@@ -83,4 +80,17 @@ internal class VotingTableViewCell: UITableViewCell {
super.init(coder: aDecoder)
}
+ // MARK: - View Life Cycle -
+
+ override func layoutSubviews() {
+ super.layoutSubviews()
+
+ titleLabel.textColor = .wkrTextColor(for: traitCollection)
+ if isSelected {
+ countLabel.textColor = .wkrVoteCountSelectedTextColor(for: traitCollection)
+ } else {
+ countLabel.textColor = .wkrVoteCountTextColor(for: traitCollection)
+ }
+ }
+
}
diff --git a/WikiRaces/Shared/Race View Controllers/VotingViewController/VotingViewController+KB.swift b/WikiRaces/Shared/Race View Controllers/VotingViewController/VotingViewController+KB.swift
index 1b85369..f63de1b 100644
--- a/WikiRaces/Shared/Race View Controllers/VotingViewController/VotingViewController+KB.swift
+++ b/WikiRaces/Shared/Race View Controllers/VotingViewController/VotingViewController+KB.swift
@@ -10,7 +10,7 @@ import UIKit
extension VotingViewController {
- // MARK: - Keyboard Support
+ // MARK: - Keyboard Support -
override var keyCommands: [UIKeyCommand]? {
var commands = [UIKeyCommand]()
diff --git a/WikiRaces/Shared/Race View Controllers/VotingViewController/VotingViewController+TableView.swift b/WikiRaces/Shared/Race View Controllers/VotingViewController/VotingViewController+TableView.swift
index faf263c..467d9ad 100644
--- a/WikiRaces/Shared/Race View Controllers/VotingViewController/VotingViewController+TableView.swift
+++ b/WikiRaces/Shared/Race View Controllers/VotingViewController/VotingViewController+TableView.swift
@@ -9,7 +9,7 @@ import UIKit
extension VotingViewController: UITableViewDataSource, UITableViewDelegate {
- // MARK: - UITableViewDataSource
+ // MARK: - UITableViewDataSource -
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return voteInfo?.pageCount ?? 0
@@ -24,7 +24,7 @@ extension VotingViewController: UITableViewDataSource, UITableViewDelegate {
return cell
}
- // MARK: - UITableViewDelegate
+ // MARK: - UITableViewDelegate -
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
guard let lastIndexPath = tableView.indexPathForSelectedRow else {
diff --git a/WikiRaces/Shared/Race View Controllers/VotingViewController/VotingViewController.swift b/WikiRaces/Shared/Race View Controllers/VotingViewController/VotingViewController.swift
index 19603a7..058c936 100644
--- a/WikiRaces/Shared/Race View Controllers/VotingViewController/VotingViewController.swift
+++ b/WikiRaces/Shared/Race View Controllers/VotingViewController/VotingViewController.swift
@@ -12,14 +12,14 @@ import WKRUIKit
internal class VotingViewController: CenteredTableViewController {
- // MARK: - Types
+ // MARK: - Types -
enum ListenerUpdate {
case voted(WKRPage)
case quit
}
- // MARK: - Properties
+ // MARK: - Properties -
private var isShowingGuide = false
private var isShowingVoteCountdown = true
@@ -70,7 +70,7 @@ internal class VotingViewController: CenteredTableViewController {
}
}
- // MARK: - View Life Cycle
+ // MARK: - View Life Cycle -
override func viewDidLoad() {
super.viewDidLoad()
@@ -101,7 +101,7 @@ internal class VotingViewController: CenteredTableViewController {
}
}
- // MARK: - Actions
+ // MARK: - Actions -
@objc func doneButtonPressed(_ sender: Any) {
PlayerAnonymousMetrics.log(event: .userAction(#function))
@@ -114,7 +114,7 @@ internal class VotingViewController: CenteredTableViewController {
present(alertController, animated: true, completion: nil)
}
- // MARK: - Helpers
+ // MARK: - Helpers -
func votingEnded() {
isShowingVoteCountdown = false
diff --git a/WikiRaces/WikiRaces (Multi-Window)/AppDelegate.swift b/WikiRaces/WikiRaces (Multi-Window)/AppDelegate.swift
index 35f6d3c..bacbe04 100644
--- a/WikiRaces/WikiRaces (Multi-Window)/AppDelegate.swift
+++ b/WikiRaces/WikiRaces (Multi-Window)/AppDelegate.swift
@@ -7,14 +7,21 @@
//
import UIKit
+import WKRUIKit
@UIApplicationMain
internal class AppDelegate: WKRAppDelegate {
//swiftlint:disable:next line_length
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
- configureAppearance()
configureConstants()
+
+ window = WKRWindow(frame: UIScreen.main.bounds)
+ let controller = ViewController()
+ let nav = WKRUINavigationController(rootViewController: controller)
+ nav.setNavigationBarHidden(true, animated: false)
+ window?.rootViewController = nav
+ window?.makeKeyAndVisible()
return true
}
diff --git a/WikiRaces/WikiRaces (Multi-Window)/Base.lproj/Main-MultiWindow.storyboard b/WikiRaces/WikiRaces (Multi-Window)/Base.lproj/Main-MultiWindow.storyboard
deleted file mode 100644
index 7ef2ecf..0000000
--- a/WikiRaces/WikiRaces (Multi-Window)/Base.lproj/Main-MultiWindow.storyboard
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/WikiRaces/WikiRaces (Multi-Window)/Info.plist b/WikiRaces/WikiRaces (Multi-Window)/Info.plist
index 0fedbe1..5d80f22 100644
--- a/WikiRaces/WikiRaces (Multi-Window)/Info.plist
+++ b/WikiRaces/WikiRaces (Multi-Window)/Info.plist
@@ -17,13 +17,11 @@
CFBundleShortVersionString
1.0
CFBundleVersion
- 857
+ 870
LSRequiresIPhoneOS
UILaunchStoryboardName
LaunchScreen
- UIMainStoryboardFile
- Main-MultiWindow
UIRequiredDeviceCapabilities
armv7
diff --git a/WikiRaces/WikiRaces (Multi-Window)/ViewController.swift b/WikiRaces/WikiRaces (Multi-Window)/ViewController.swift
index 7143cd5..45952fd 100644
--- a/WikiRaces/WikiRaces (Multi-Window)/ViewController.swift
+++ b/WikiRaces/WikiRaces (Multi-Window)/ViewController.swift
@@ -11,6 +11,8 @@ import UIKit
//swiftlint:disable line_length function_body_length force_cast superfluous_disable_command
class ViewController: UIViewController {
+ var windows = [DebugWindow]()
+
override func viewDidLoad() {
super.viewDidLoad()
@@ -53,7 +55,7 @@ class ViewController: UIViewController {
createDebugWindow(frame: frame, named: name)
}
}
- view.backgroundColor = UIColor.purple
+ view.backgroundColor = .purple
}
func createDebugWindow(frame: CGRect, named name: String) {
@@ -61,6 +63,7 @@ class ViewController: UIViewController {
window.playerName = name
window.rootViewController = MenuViewController()
window.makeKeyAndVisible()
+ windows.append(window)
}
}
diff --git a/WikiRaces/WikiRaces (UI Catalog)/AppDelegate.swift b/WikiRaces/WikiRaces (UI Catalog)/AppDelegate.swift
index 1be58c7..b1da5a6 100644
--- a/WikiRaces/WikiRaces (UI Catalog)/AppDelegate.swift
+++ b/WikiRaces/WikiRaces (UI Catalog)/AppDelegate.swift
@@ -13,9 +13,7 @@ class AppDelegate: WKRAppDelegate {
//swiftlint:disable:next line_length
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
- configureAppearance()
configureConstants()
-
cleanTempDirectory()
return true
}
diff --git a/WikiRaces/WikiRaces.xcodeproj/project.pbxproj b/WikiRaces/WikiRaces.xcodeproj/project.pbxproj
index f72ad0a..15206f6 100644
--- a/WikiRaces/WikiRaces.xcodeproj/project.pbxproj
+++ b/WikiRaces/WikiRaces.xcodeproj/project.pbxproj
@@ -3,19 +3,21 @@
archiveVersion = 1;
classes = {
};
- objectVersion = 48;
+ objectVersion = 52;
objects = {
/* Begin PBXBuildFile section */
- 140564D52112D4BD001E36AB /* Crashlytics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 140564D32112D4BC001E36AB /* Crashlytics.framework */; };
- 140564D62112D4BD001E36AB /* Fabric.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 140564D42112D4BC001E36AB /* Fabric.framework */; };
+ 140564D52112D4BD001E36AB /* Crashlytics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 140564D32112D4BC001E36AB /* Crashlytics.framework */; platformFilter = ios; };
+ 140564D62112D4BD001E36AB /* Fabric.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 140564D42112D4BC001E36AB /* Fabric.framework */; platformFilter = ios; };
+ 140C78D82377AD0D0034F6DE /* UIFont+Rounded.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140C78D52377AD0D0034F6DE /* UIFont+Rounded.swift */; };
+ 140C78D92377AD0D0034F6DE /* UIFont+Rounded.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140C78D52377AD0D0034F6DE /* UIFont+Rounded.swift */; };
+ 140C78DA2377AD0D0034F6DE /* UIFont+Rounded.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140C78D52377AD0D0034F6DE /* UIFont+Rounded.swift */; };
1410DB3B1F4F510900F5CAD7 /* SharedAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1410DB3A1F4F510900F5CAD7 /* SharedAssets.xcassets */; };
1410DB3D1F4F510900F5CAD7 /* SharedAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1410DB3A1F4F510900F5CAD7 /* SharedAssets.xcassets */; };
1414280321FC18F600C48788 /* GameKitConnectViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1414280221FC18F600C48788 /* GameKitConnectViewController.swift */; };
1414280721FC394600C48788 /* ConnectViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1414280621FC394600C48788 /* ConnectViewController.swift */; };
1414280B21FC437000C48788 /* GameKitConnectViewController+Match.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1414280A21FC437000C48788 /* GameKitConnectViewController+Match.swift */; };
- 141598DF2201493E00DA955E /* FirebaseRemoteConfig.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 141598DC2201493D00DA955E /* FirebaseRemoteConfig.framework */; };
- 141598E12201495F00DA955E /* FirebaseABTesting.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 141598E02201495F00DA955E /* FirebaseABTesting.framework */; };
+ 141854DF2373666A008C988A /* MPCHostAutoInviteCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 141854DE2373666A008C988A /* MPCHostAutoInviteCell.swift */; };
141892F41F60EABC006748F0 /* MPCConnectViewController+Invite.swift in Sources */ = {isa = PBXBuildFile; fileRef = 141892F31F60EABC006748F0 /* MPCConnectViewController+Invite.swift */; };
141E4CE72200DDD6000A0A15 /* ResultsViewController+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 141E4CE62200DDD6000A0A15 /* ResultsViewController+Actions.swift */; };
141E4CE82200DDD6000A0A15 /* ResultsViewController+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 141E4CE62200DDD6000A0A15 /* ResultsViewController+Actions.swift */; };
@@ -60,22 +62,12 @@
1478B1B122095360009F2F3F /* ResultRenderer+Creation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1478B1B022095360009F2F3F /* ResultRenderer+Creation.swift */; };
1478B1B222095360009F2F3F /* ResultRenderer+Creation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1478B1B022095360009F2F3F /* ResultRenderer+Creation.swift */; };
1478B1B322095360009F2F3F /* ResultRenderer+Creation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1478B1B022095360009F2F3F /* ResultRenderer+Creation.swift */; };
+ 14794CA9236C884B00835DC9 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 14794CA8236C884A00835DC9 /* GoogleService-Info.plist */; };
147EF6F92202436600583D73 /* MPCHostContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 147EF6F82202436600583D73 /* MPCHostContext.swift */; };
147EF6FA2202436600583D73 /* MPCHostContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 147EF6F82202436600583D73 /* MPCHostContext.swift */; };
147EF7122202D76000583D73 /* MPCHostContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 147EF6F82202436600583D73 /* MPCHostContext.swift */; };
1480F6C321FB77D300081F58 /* DebugInfoTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 143948BC2144CC0F00992850 /* DebugInfoTableViewController.swift */; };
1480F6C621FB77DE00081F58 /* DebugInfoTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 143948C02144CC8C00992850 /* DebugInfoTableViewCell.swift */; };
- 148487F8214F0F3B0098CBFA /* GoogleToolboxForMac.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 148487EC214F0F3A0098CBFA /* GoogleToolboxForMac.framework */; };
- 148487F9214F0F3B0098CBFA /* GoogleUtilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 148487ED214F0F3A0098CBFA /* GoogleUtilities.framework */; };
- 148487FA214F0F3B0098CBFA /* Protobuf.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 148487EE214F0F3A0098CBFA /* Protobuf.framework */; };
- 148487FB214F0F3B0098CBFA /* FirebaseCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 148487EF214F0F3B0098CBFA /* FirebaseCore.framework */; };
- 148487FC214F0F3B0098CBFA /* nanopb.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 148487F0214F0F3B0098CBFA /* nanopb.framework */; };
- 148487FE214F0F3B0098CBFA /* FirebaseInstanceID.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 148487F2214F0F3B0098CBFA /* FirebaseInstanceID.framework */; };
- 148487FF214F0F3B0098CBFA /* GoogleAppMeasurement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 148487F3214F0F3B0098CBFA /* GoogleAppMeasurement.framework */; };
- 14848800214F0F3B0098CBFA /* FirebasePerformance.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 148487F4214F0F3B0098CBFA /* FirebasePerformance.framework */; };
- 14848801214F0F3B0098CBFA /* GTMSessionFetcher.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 148487F5214F0F3B0098CBFA /* GTMSessionFetcher.framework */; };
- 14848802214F0F3B0098CBFA /* FirebaseCoreDiagnostics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 148487F6214F0F3B0098CBFA /* FirebaseCoreDiagnostics.framework */; };
- 14848803214F0F3B0098CBFA /* FirebaseAnalytics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 148487F7214F0F3B0098CBFA /* FirebaseAnalytics.framework */; };
1485B6772230724A00D6800B /* MedalScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1485B6762230724A00D6800B /* MedalScene.swift */; };
1485B6782230724A00D6800B /* MedalScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1485B6762230724A00D6800B /* MedalScene.swift */; };
1485B6792230724A00D6800B /* MedalScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1485B6762230724A00D6800B /* MedalScene.swift */; };
@@ -97,12 +89,30 @@
149FF8571F362B83000A5D96 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 149FF8551F362B83000A5D96 /* LaunchScreen.storyboard */; };
149FF87B1F362BE4000A5D96 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 149FF87A1F362BE4000A5D96 /* AppDelegate.swift */; };
149FF87D1F362BE4000A5D96 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 149FF87C1F362BE4000A5D96 /* ViewController.swift */; };
- 149FF8801F362BE4000A5D96 /* Main-MultiWindow.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 149FF87E1F362BE4000A5D96 /* Main-MultiWindow.storyboard */; };
149FF8821F362BE4000A5D96 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 149FF8811F362BE4000A5D96 /* Assets.xcassets */; };
149FF8851F362BE4000A5D96 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 149FF8831F362BE4000A5D96 /* LaunchScreen.storyboard */; };
149FF8911F362BF1000A5D96 /* WikiRacesScreenshots.swift in Sources */ = {isa = PBXBuildFile; fileRef = 149FF8901F362BF1000A5D96 /* WikiRacesScreenshots.swift */; };
+ 14A35E5F23660823002BCBF6 /* FirebaseCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A35E4D23660821002BCBF6 /* FirebaseCore.framework */; platformFilter = ios; };
+ 14A35E6023660823002BCBF6 /* GTMSessionFetcher.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A35E5023660821002BCBF6 /* GTMSessionFetcher.framework */; platformFilter = ios; };
+ 14A35E6123660823002BCBF6 /* GoogleToolboxForMac.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A35E5123660822002BCBF6 /* GoogleToolboxForMac.framework */; platformFilter = ios; };
+ 14A35E6223660823002BCBF6 /* GoogleDataTransportCCTSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A35E5223660822002BCBF6 /* GoogleDataTransportCCTSupport.framework */; platformFilter = ios; };
+ 14A35E6323660823002BCBF6 /* FirebaseCoreDiagnostics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A35E5323660822002BCBF6 /* FirebaseCoreDiagnostics.framework */; platformFilter = ios; };
+ 14A35E6423660823002BCBF6 /* GoogleAppMeasurement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A35E5423660822002BCBF6 /* GoogleAppMeasurement.framework */; platformFilter = ios; };
+ 14A35E6523660823002BCBF6 /* nanopb.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A35E5523660822002BCBF6 /* nanopb.framework */; platformFilter = ios; };
+ 14A35E6623660823002BCBF6 /* FirebaseInstanceID.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A35E5623660822002BCBF6 /* FirebaseInstanceID.framework */; platformFilter = ios; };
+ 14A35E6723660823002BCBF6 /* FirebaseRemoteConfig.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A35E5723660822002BCBF6 /* FirebaseRemoteConfig.framework */; platformFilter = ios; };
+ 14A35E6823660823002BCBF6 /* FirebaseABTesting.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A35E5823660822002BCBF6 /* FirebaseABTesting.framework */; platformFilter = ios; };
+ 14A35E6923660823002BCBF6 /* FirebaseAnalytics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A35E5923660823002BCBF6 /* FirebaseAnalytics.framework */; platformFilter = ios; };
+ 14A35E6A23660823002BCBF6 /* FIRAnalyticsConnector.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A35E5A23660823002BCBF6 /* FIRAnalyticsConnector.framework */; platformFilter = ios; };
+ 14A35E6B23660823002BCBF6 /* GoogleDataTransport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A35E5B23660823002BCBF6 /* GoogleDataTransport.framework */; platformFilter = ios; };
+ 14A35E6C23660823002BCBF6 /* GoogleUtilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A35E5C23660823002BCBF6 /* GoogleUtilities.framework */; platformFilter = ios; };
+ 14A35E6D23660823002BCBF6 /* Protobuf.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A35E5D23660823002BCBF6 /* Protobuf.framework */; platformFilter = ios; };
+ 14A35E6E23660823002BCBF6 /* FirebasePerformance.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A35E5E23660823002BCBF6 /* FirebasePerformance.framework */; platformFilter = ios; };
14A7C9B31F65A9EB00980E4D /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 143BB7321F60DE9300D00541 /* Settings.bundle */; };
14A89F681F7ABB2400C85387 /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14E1B1A01F798A520082F4FA /* CloudKit.framework */; };
+ 14AD1E8022F78A2300DFEEE1 /* WKRWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14AD1E7F22F78A2300DFEEE1 /* WKRWindow.swift */; };
+ 14AD1E8122F78A2300DFEEE1 /* WKRWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14AD1E7F22F78A2300DFEEE1 /* WKRWindow.swift */; };
+ 14AD1E8222F78A2300DFEEE1 /* WKRWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14AD1E7F22F78A2300DFEEE1 /* WKRWindow.swift */; };
14B2DD3B22212298009B8AB3 /* MenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14B2DD3A22212298009B8AB3 /* MenuView.swift */; };
14B2DD3C22212298009B8AB3 /* MenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14B2DD3A22212298009B8AB3 /* MenuView.swift */; };
14B2DD3D22212298009B8AB3 /* MenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14B2DD3A22212298009B8AB3 /* MenuView.swift */; };
@@ -126,7 +136,7 @@
14B4DB6C2224FA54007D4B54 /* MPCHostSoloCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14B4DB6A2224FA54007D4B54 /* MPCHostSoloCell.swift */; };
14B4DB6D2224FA54007D4B54 /* MPCHostSoloCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14B4DB6A2224FA54007D4B54 /* MPCHostSoloCell.swift */; };
14B55C991F3A49D20090E092 /* DebugWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14B55C981F3A49D20090E092 /* DebugWindow.swift */; };
- 14B8F80D222C456B006C7A06 /* GameKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14B8F80C222C456B006C7A06 /* GameKit.framework */; };
+ 14B8F80D222C456B006C7A06 /* GameKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14B8F80C222C456B006C7A06 /* GameKit.framework */; platformFilter = ios; };
14B8F811222C47FA006C7A06 /* GKMessageImage.png in Resources */ = {isa = PBXBuildFile; fileRef = 14B8F810222C47FA006C7A06 /* GKMessageImage.png */; };
14BA538921FE3B1400A8CB01 /* ConnectViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1414280621FC394600C48788 /* ConnectViewController.swift */; };
14BA538D21FE3D9100A8CB01 /* MenuViewController+Debug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14BA538C21FE3D9100A8CB01 /* MenuViewController+Debug.swift */; };
@@ -189,8 +199,6 @@
14C6B1F71FF2EABD00F6B422 /* MPCHostSearchingCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14C6B1F31FF2EABC00F6B422 /* MPCHostSearchingCell.swift */; };
14D8AD471F81828D00914E5A /* PlayerAnonymousMetrics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14E1B1991F7981C70082F4FA /* PlayerAnonymousMetrics.swift */; };
14D8AD481F81835700914E5A /* DebugWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14B55C981F3A49D20090E092 /* DebugWindow.swift */; };
- 14DC66D11F90700A0026C6ED /* fabric.apikey in Resources */ = {isa = PBXBuildFile; fileRef = 143BB72F1F60D84100D00541 /* fabric.apikey */; };
- 14DC66D21F90700D0026C6ED /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 143054BD1F89581100C0BC27 /* GoogleService-Info.plist */; };
14DC66D31F9072180026C6ED /* WKRKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14E6D55A1F86A1B0005EB3B9 /* WKRKit.framework */; };
14DC66D41F9072180026C6ED /* WKRKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 14E6D55A1F86A1B0005EB3B9 /* WKRKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
14DC66D71F9072200026C6ED /* WKRUIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14E6D5521F86A1B0005EB3B9 /* WKRUIKit.framework */; };
@@ -368,12 +376,12 @@
/* Begin PBXFileReference section */
140564D32112D4BC001E36AB /* Crashlytics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Crashlytics.framework; sourceTree = ""; };
140564D42112D4BC001E36AB /* Fabric.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Fabric.framework; sourceTree = ""; };
+ 140C78D52377AD0D0034F6DE /* UIFont+Rounded.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIFont+Rounded.swift"; sourceTree = ""; };
1410DB3A1F4F510900F5CAD7 /* SharedAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = SharedAssets.xcassets; sourceTree = ""; };
1414280221FC18F600C48788 /* GameKitConnectViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameKitConnectViewController.swift; sourceTree = ""; };
1414280621FC394600C48788 /* ConnectViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectViewController.swift; sourceTree = ""; };
1414280A21FC437000C48788 /* GameKitConnectViewController+Match.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GameKitConnectViewController+Match.swift"; sourceTree = ""; };
- 141598DC2201493D00DA955E /* FirebaseRemoteConfig.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = FirebaseRemoteConfig.framework; sourceTree = ""; };
- 141598E02201495F00DA955E /* FirebaseABTesting.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = FirebaseABTesting.framework; sourceTree = ""; };
+ 141854DE2373666A008C988A /* MPCHostAutoInviteCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPCHostAutoInviteCell.swift; sourceTree = ""; };
141892F31F60EABC006748F0 /* MPCConnectViewController+Invite.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MPCConnectViewController+Invite.swift"; sourceTree = ""; };
141E4CE62200DDD6000A0A15 /* ResultsViewController+Actions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ResultsViewController+Actions.swift"; sourceTree = ""; };
141E4CF022012B2F000A0A15 /* PlayerDatabaseMetrics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerDatabaseMetrics.swift; sourceTree = ""; };
@@ -382,15 +390,12 @@
142F7152210C34A300C66558 /* MPCHostViewController+KB.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MPCHostViewController+KB.swift"; sourceTree = ""; };
142F7154210C35BC00C66558 /* VotingViewController+KB.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VotingViewController+KB.swift"; sourceTree = ""; };
142F7156210C375F00C66558 /* GameViewController+KB.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GameViewController+KB.swift"; sourceTree = ""; };
- 143054BD1F89581100C0BC27 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; };
143054D01F8959DA00C0BC27 /* BridgingHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BridgingHeader.h; sourceTree = ""; };
1437C51E22285FE30003E53B /* HistoryTableViewStatsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryTableViewStatsCell.swift; sourceTree = ""; };
143948BC2144CC0F00992850 /* DebugInfoTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugInfoTableViewController.swift; sourceTree = ""; };
143948C02144CC8C00992850 /* DebugInfoTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugInfoTableViewCell.swift; sourceTree = ""; };
143A8BBB1F58746800580AA2 /* PlayerStatsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerStatsManager.swift; sourceTree = ""; };
143BB7171F60BDC000D00541 /* MenuViewController+GameKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MenuViewController+GameKit.swift"; sourceTree = ""; };
- 143BB72E1F60D84100D00541 /* fabric.buildsecret */ = {isa = PBXFileReference; lastKnownFileType = text; path = fabric.buildsecret; sourceTree = SOURCE_ROOT; };
- 143BB72F1F60D84100D00541 /* fabric.apikey */ = {isa = PBXFileReference; lastKnownFileType = text; path = fabric.apikey; sourceTree = SOURCE_ROOT; };
143BB7321F60DE9300D00541 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = ""; };
143BB7341F60DF4A00D00541 /* MPCConnectViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPCConnectViewController.swift; sourceTree = ""; };
144280EC1F5883AB002D977F /* WikiRaces.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WikiRaces.entitlements; sourceTree = ""; };
@@ -407,18 +412,8 @@
147593CF1F609902005DFC90 /* Snapfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Snapfile; sourceTree = SOURCE_ROOT; };
147593D01F609911005DFC90 /* SnapshotHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnapshotHelper.swift; sourceTree = ""; };
1478B1B022095360009F2F3F /* ResultRenderer+Creation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ResultRenderer+Creation.swift"; sourceTree = ""; };
+ 14794CA8236C884A00835DC9 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; };
147EF6F82202436600583D73 /* MPCHostContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MPCHostContext.swift; path = "Shared/Menu View Controllers/Connect View Controllers/Multipeer Connectivity/MPCHostContext.swift"; sourceTree = SOURCE_ROOT; };
- 148487EC214F0F3A0098CBFA /* GoogleToolboxForMac.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = GoogleToolboxForMac.framework; sourceTree = ""; };
- 148487ED214F0F3A0098CBFA /* GoogleUtilities.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = GoogleUtilities.framework; sourceTree = ""; };
- 148487EE214F0F3A0098CBFA /* Protobuf.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Protobuf.framework; sourceTree = ""; };
- 148487EF214F0F3B0098CBFA /* FirebaseCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = FirebaseCore.framework; sourceTree = ""; };
- 148487F0214F0F3B0098CBFA /* nanopb.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = nanopb.framework; sourceTree = ""; };
- 148487F2214F0F3B0098CBFA /* FirebaseInstanceID.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = FirebaseInstanceID.framework; sourceTree = ""; };
- 148487F3214F0F3B0098CBFA /* GoogleAppMeasurement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = GoogleAppMeasurement.framework; sourceTree = ""; };
- 148487F4214F0F3B0098CBFA /* FirebasePerformance.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = FirebasePerformance.framework; sourceTree = ""; };
- 148487F5214F0F3B0098CBFA /* GTMSessionFetcher.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = GTMSessionFetcher.framework; sourceTree = ""; };
- 148487F6214F0F3B0098CBFA /* FirebaseCoreDiagnostics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = FirebaseCoreDiagnostics.framework; sourceTree = ""; };
- 148487F7214F0F3B0098CBFA /* FirebaseAnalytics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = FirebaseAnalytics.framework; sourceTree = ""; };
1485B6762230724A00D6800B /* MedalScene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MedalScene.swift; sourceTree = ""; };
1485B67C223072AB00D6800B /* MedalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MedalView.swift; sourceTree = ""; };
149357D8210E801A00F6453A /* HistoryViewController+KB.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryViewController+KB.swift"; sourceTree = ""; };
@@ -432,14 +427,30 @@
149FF8781F362BE4000A5D96 /* WikiRaces (Multi-Window).app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "WikiRaces (Multi-Window).app"; sourceTree = BUILT_PRODUCTS_DIR; };
149FF87A1F362BE4000A5D96 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
149FF87C1F362BE4000A5D96 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
- 149FF87F1F362BE4000A5D96 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = "Base.lproj/Main-MultiWindow.storyboard"; sourceTree = ""; };
149FF8811F362BE4000A5D96 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
149FF8841F362BE4000A5D96 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
149FF8861F362BE4000A5D96 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
149FF88E1F362BF1000A5D96 /* WikiRacesScreenshots.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WikiRacesScreenshots.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
149FF8901F362BF1000A5D96 /* WikiRacesScreenshots.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WikiRacesScreenshots.swift; sourceTree = ""; };
149FF8921F362BF1000A5D96 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ 14A35E4D23660821002BCBF6 /* FirebaseCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = FirebaseCore.framework; sourceTree = ""; };
+ 14A35E5023660821002BCBF6 /* GTMSessionFetcher.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = GTMSessionFetcher.framework; sourceTree = ""; };
+ 14A35E5123660822002BCBF6 /* GoogleToolboxForMac.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = GoogleToolboxForMac.framework; sourceTree = ""; };
+ 14A35E5223660822002BCBF6 /* GoogleDataTransportCCTSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = GoogleDataTransportCCTSupport.framework; sourceTree = ""; };
+ 14A35E5323660822002BCBF6 /* FirebaseCoreDiagnostics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = FirebaseCoreDiagnostics.framework; sourceTree = "